diff options
author | Gwenolé Beauchesne <gbeauchesne@mandriva.org> | 2003-06-04 18:44:09 +0000 |
---|---|---|
committer | Gwenolé Beauchesne <gbeauchesne@mandriva.org> | 2003-06-04 18:44:09 +0000 |
commit | 4cd6a4a5d7e49d54d53dcf4a6f3393d50bd88e8b (patch) | |
tree | acd4001a266a8713495af7f1b2102b61e67113b0 /mdk-stage1/dietlibc/lib/bcd.c | |
parent | 71b111ec6c4671667a19c6fbe0023d33422535d7 (diff) | |
download | drakx-4cd6a4a5d7e49d54d53dcf4a6f3393d50bd88e8b.tar drakx-4cd6a4a5d7e49d54d53dcf4a6f3393d50bd88e8b.tar.gz drakx-4cd6a4a5d7e49d54d53dcf4a6f3393d50bd88e8b.tar.bz2 drakx-4cd6a4a5d7e49d54d53dcf4a6f3393d50bd88e8b.tar.xz drakx-4cd6a4a5d7e49d54d53dcf4a6f3393d50bd88e8b.zip |
Import dietlibc 0.22 + other fixes for AMD64
Diffstat (limited to 'mdk-stage1/dietlibc/lib/bcd.c')
-rw-r--r-- | mdk-stage1/dietlibc/lib/bcd.c | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/mdk-stage1/dietlibc/lib/bcd.c b/mdk-stage1/dietlibc/lib/bcd.c new file mode 100644 index 000000000..1936b82f6 --- /dev/null +++ b/mdk-stage1/dietlibc/lib/bcd.c @@ -0,0 +1,185 @@ + +static long double powers [] = { + 1.e+1, 1.e+2, 1.e+4, 1.e+8, 1.e+16, 1.e+32, 1.e+64, 1.e+128, 1.e+256 +}; + +/* + * So, die ist zum Zerlegen von Gleitkommazahlen am besten geeignet. + * + * Die nichtnegative übergebende Gleitkommazahl number wird in einen + * Exponenten e und eine Mantisse m zerlegt mit: + * + * 1 <= m < 10 + * number = m * 10^e + * + * Die Mantisse wird in precision Dezimalstellen zerlegt, die nach digits + * geschrieben werden. digits[0] ist die Vorkommastelle, digits [1 ... + * precision-1] die Nachkommastellen der Mantisse Zurückgeliefert wird der + * Exponent. + * + * Für precision ist ein Wert von 0 erlaubt, Sinn machen allerdings erst + * Werte ab 1. + */ + +int __decompose_floatp ( long double number, + unsigned char* digits, unsigned int precision ); + +int __decompose_floatp ( long double number, + unsigned char* digits, unsigned int precision ) +{ + int ret = 0; + int i; + double tmp; + + if ( number > 0.L ) { + + // Exponent abtrennen + if ( number >= 10.L ) { + for ( i = sizeof(powers)/sizeof(*powers)-1; i >= 0; i--) + if ( number >= powers [i] ) { + number /= powers [i]; + ret += 1 << i; + } + } else if ( number < 1.L ) + for ( i = sizeof(powers)/sizeof(*powers)-1; i >= 0; i--) + if ( number * powers [i] < 10.L ) { + number *= powers [i]; + ret -= 1 << i; + } + + // Runden (ohne Geradezahlregel => Bug) + tmp = 5.; + { + unsigned int j; + for ( j = 0; j < precision; j++ ) + tmp *= 0.1; + } + + number += tmp; + + // Dabei kann die Zahl in die nächste Dekade reinrutschen ... + if ( number >= 10.L ) { + number = 1.L; + ret++; + } + } + + // Mantisse in ASCII konvertieren + while ( precision-- ) { + i = (int) number; + number = (number - i) * 10.L; + *digits++ = '0' + i; + } + + // Exponent zurück + return ret; +} + + +/* + * So, die ist zum Zerlegen von Festkommazahlen am besten geeignet. + * + * Die nichtnegative übergebende Festkomma wird in einen Integeranteil und + * einen Bruchanteil zerlegt. + * + * Der Bruchanteil wird in digits_frac[0...precision_frac-1] gespeichert, + * falls precision_frac != 0 ist. + * + * Der Integeranteil wird ab digits_int + precision_int - 1 rückwrts + * geschrieben. Zurückgeliefert wird ein Zeiger auf das erste Zeichen, das + * bei der Konvertierung != '0' ist (Ausnahme ist die 0.0 selbst). Zeichen + * zwischen digits_int und diesem Zeiger (exklusive des Zeichens unter dem + * Zeiger) sind unbestimmt. Wünscht man dort Nullen oder Leerzeichen, + * sollte man mittels memset() dieses vorher initialsieren. + */ + +char* __decompose_fixp ( long double number, + unsigned char* digits_int , unsigned int precision_int, + unsigned char* digits_frac, unsigned int precision_frac ); + +char* __decompose_fixp ( long double number, + unsigned char* digits_int , unsigned int precision_int, + unsigned char* digits_frac, unsigned int precision_frac ) +{ + long long int integer; + double tmp; + int i; + + // Runden (ohne Geradezahlregel => Bug) + tmp = 0.5; + { + unsigned int j; + for ( j = 0; j < precision_frac; j++ ) + tmp *= 0.1; + } + + number += tmp; + + integer = number; + number -= integer; + + // Nachkommastellen + while ( precision_frac-- ) { + number *= 10.L; + i = (int) number; + number -= i; + *digits_frac++ + = '0' + i; + } + + // Vorkommastellen + while ( precision_int ) { + i = (int) (integer % 10); + integer /= 10; + digits_int [--precision_int] + = '0' + i; + if ( integer == 0 ) + break; + } + + return digits_int + precision_int; +} + + +#if 0 + +#include <stdio.h> +#include <math.h> + +long double test [] = { + 1, M_PI, 123, 123456789, 12345678901234567, 1e300, 0.00123456789, 1.234567890123456e-300, 0 +}; + +int main ( void ) +{ + int i; + int j; + int k; + char buff1 [32]; + char buff2 [32]; + char* retp; + int ret; + + for ( i = 0; i < sizeof(test)/sizeof(*test); i++ ) { + printf ("\n*** %30.20Lf ***\n\n", test[i] ); + + for ( j = 0; j <= 20; j++ ) { + memset ( buff1, 0, sizeof(buff1) ); + ret = __decompose_floatp ( test[i], buff1, j ); + printf ( "floatp(%2u) = <%sE%+d>\n", j, buff1, ret ); + } + for ( j = 0; j <= 20; j++ ) { + for ( k = 0; k <= 20; k++ ) { + memset ( buff1, 0, sizeof(buff1) ); + memset ( buff2, 0, sizeof(buff2) ); + retp = __decompose_fixp ( test[i], buff1, j, buff2, k ); + printf ( "fixp(%2u,%2u) = <%s.%s>\n", j, k, retp, buff2 ); + } + } + + } + + return 0; +} + +#endif |