Changeset d43c117 in mainline


Ignore:
Timestamp:
2011-07-24T21:26:19Z (13 years ago)
Author:
Jiří Zárevúcky <zarevucky.jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
d542aad
Parents:
cfbb5d18
Message:

Changes to strtold(). Should work on all platforms now.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/posix/stdlib/strtold.c

    rcfbb5d18 rd43c117  
    4646#include "../strings.h"
    4747#include "../errno.h"
     48#include "../limits.h"
     49
     50// FIXME: #include <float.h>
    4851
    4952#ifndef HUGE_VALL
     
    5255
    5356#ifndef abs
    54         #define abs(x) ((x < 0) ? -x : x)
    55 #endif
    56 
    57 // TODO: clean up
    58 
    59 // FIXME: ensure it builds and works on all platforms
    60 
    61 const int max_small_pow5 = 15;
    62 
    63 /* The value at index i is approximately 5**i. */
    64 long double small_pow5[] = {
    65         0x1P0,
    66         0x5P0,
    67         0x19P0,
    68         0x7dP0,
    69         0x271P0,
    70         0xc35P0,
    71         0x3d09P0,
    72         0x1312dP0,
    73         0x5f5e1P0,
    74         0x1dcd65P0,
    75         0x9502f9P0,
    76         0x2e90eddP0,
    77         0xe8d4a51P0,
    78         0x48c27395P0,
    79         0x16bcc41e9P0,
    80         0x71afd498dP0
     57        #define abs(x) (((x) < 0) ? -(x) : (x))
     58#endif
     59
     60/* If the constants are not defined, use double precision as default. */
     61#ifndef LDBL_MANT_DIG
     62        #define LDBL_MANT_DIG 53
     63#endif
     64#ifndef LDBL_MAX_EXP
     65        #define LDBL_MAX_EXP 1024
     66#endif
     67#ifndef LDBL_MIN_EXP
     68        #define LDBL_MIN_EXP (-1021)
     69#endif
     70#ifndef LDBL_DIG
     71        #define LDBL_DIG 15
     72#endif
     73#ifndef LDBL_MIN
     74        #define LDBL_MIN 2.2250738585072014E-308
     75#endif
     76
     77/* power functions ************************************************************/
     78
     79#if LDBL_MAX_EXP >= 16384
     80const int MAX_POW5 = 12;
     81#else
     82const int MAX_POW5 = 8;
     83#endif
     84
     85/* The value at index i is approximately 5**(2**i). */
     86long double pow5[] = {
     87        0x5p0l,
     88        0x19p0l,
     89        0x271p0l,
     90        0x5F5E1p0l,
     91        0x2386F26FC1p0l,
     92        0x4EE2D6D415B85ACEF81p0l,
     93        0x184F03E93FF9F4DAA797ED6E38ED6p36l,
     94        0x127748F9301D319BF8CDE66D86D62p185l,
     95        0x154FDD7F73BF3BD1BBB77203731FDp482l,
     96#if LDBL_MAX_EXP >= 16384
     97        0x1C633415D4C1D238D98CAB8A978A0p1076l,
     98        0x192ECEB0D02EA182ECA1A7A51E316p2265l,
     99        0x13D1676BB8A7ABBC94E9A519C6535p4643l,
     100        0x188C0A40514412F3592982A7F0094p9398l,
     101#endif
    81102};
    82103
    83 /* The value at index i is approximately 5**(2**i). */
    84 long double large_pow5[] = {
    85         0x5P0l,
    86         0x19P0l,
    87         0x271P0l,
    88         0x5f5e1P0l,
    89         0x2386f26fc1P0l,
    90         0x4ee2d6d415b85acef81P0l,
    91         0x184f03e93ff9f4daa797ed6e38ed64bf6a1f01P0l,
    92         0x24ee91f2603a6337f19bccdb0dac404dc08d3cff5ecP128l,
    93         0x553f75fdcefcef46eeddcP512l,
    94         0x1c633415d4c1d238d98cab8a978a0b1f138cb07303P1024l,
    95         0x325d9d61a05d4305d9434f4a3c62d433949ae6209d492P2200l,
    96         0x9e8b3b5dc53d5de4a74d28ce329ace526a3197bbebe3034f77154ce2bcba1964P4500l,
    97         0x6230290145104bcd64a60a9fc025254932bb0fd922271133eeae7P9300l
    98 };
     104#if LDBL_MAX_EXP >= 16384
     105const int MAX_POW2 = 15;
     106#else
     107const int MAX_POW2 = 9;
     108#endif
    99109
    100110/* Powers of two. */
     
    110120        0x1P256l,
    111121        0x1P512l,
     122#if LDBL_MAX_EXP >= 16384
    112123        0x1P1024l,
    113124        0x1P2048l,
    114125        0x1P4096l,
    115         0x1P8192l
     126        0x1P8192l,
     127#endif
    116128};
    117129
    118130/**
    119  * Decides whether the argument is still in range representable by
    120  * long double or not.
    121  *
    122  * @param num Floating point number to be checked.
    123  * @return True if the argument is out of range, false otherwise.
    124  */
    125 static inline bool out_of_range(long double num)
    126 {
    127         return num == 0.0l || num == HUGE_VALL;
    128 }
    129 
    130 /**
    131131 * Multiplies a number by a power of five.
    132  * The result is not exact and may not be the best possible approximation.
    133  *
    134  * @param base Number to be multiplied.
    135  * @param exponent Base 5 exponent.
    136  * @return base multiplied by 5**exponent.
    137  */
    138 static long double mul_pow5(long double base, int exponent)
    139 {
    140         if (out_of_range(base)) {
    141                 return base;
    142         }
    143        
    144         if (abs(exponent) >> 13 != 0) {
     132 * The result may be inexact and may not be the best possible approximation.
     133 *
     134 * @param mant Number to be multiplied.
     135 * @param exp Base 5 exponent.
     136 * @return mant multiplied by 5**exp
     137 */
     138static long double mul_pow5(long double mant, int exp)
     139{
     140        if (mant == 0.0l || mant == HUGE_VALL) {
     141                return mant;
     142        }
     143       
     144        if (abs(exp) >> (MAX_POW5 + 1) != 0) {
     145                /* Too large exponent. */
    145146                errno = ERANGE;
    146                 return exponent < 0 ? 0.0l : HUGE_VALL;
    147         }
    148        
    149         if (exponent < 0) {
    150                 exponent = -exponent;
    151                 base /= small_pow5[exponent & 0xF];
    152                 for (int i = 4; i < 13; ++i) {
    153                         if (((exponent >> i) & 1) != 0) {
    154                                 base /= large_pow5[i];
    155                                 if (out_of_range(base)) {
     147                return exp < 0 ? LDBL_MIN : HUGE_VALL;
     148        }
     149       
     150        if (exp < 0) {
     151                exp = abs(exp);
     152                for (int bit = 0; bit <= MAX_POW5; ++bit) {
     153                        /* Multiply by powers of five bit-by-bit. */
     154                        if (((exp >> bit) & 1) != 0) {
     155                                mant /= pow5[bit];
     156                                if (mant == 0.0l) {
     157                                        /* Underflow. */
     158                                        mant = LDBL_MIN;
    156159                                        errno = ERANGE;
    157160                                        break;
     
    160163                }
    161164        } else {
    162                 base *= small_pow5[exponent & 0xF];
    163                 for (int i = 4; i < 13; ++i) {
    164                         if (((exponent >> i) & 1) != 0) {
    165                                 base *= large_pow5[i];
    166                                 if (out_of_range(base)) {
     165                for (int bit = 0; bit <= MAX_POW5; ++bit) {
     166                        /* Multiply by powers of five bit-by-bit. */
     167                        if (((exp >> bit) & 1) != 0) {
     168                                mant *= pow5[bit];
     169                                if (mant == HUGE_VALL) {
     170                                        /* Overflow. */
    167171                                        errno = ERANGE;
    168172                                        break;
     
    172176        }
    173177       
    174         return base;
    175 }
    176 
    177 /**
    178  * Multiplies a number by a power of two.
    179  *
    180  * @param base Number to be multiplied.
    181  * @param exponent Base 2 exponent.
    182  * @return base multiplied by 2**exponent.
    183  */
    184 static long double mul_pow2(long double base, int exponent)
    185 {
    186         if (out_of_range(base)) {
    187                 return base;
    188         }
    189        
    190         if (abs(exponent) >> 14 != 0) {
     178        return mant;
     179}
     180
     181/**
     182 * Multiplies a number by a power of two. This is always exact.
     183 *
     184 * @param mant Number to be multiplied.
     185 * @param exp Base 2 exponent.
     186 * @return mant multiplied by 2**exp.
     187 */
     188static long double mul_pow2(long double mant, int exp)
     189{
     190        if (mant == 0.0l || mant == HUGE_VALL) {
     191                return mant;
     192        }
     193       
     194        if (exp > LDBL_MAX_EXP || exp < LDBL_MIN_EXP) {
    191195                errno = ERANGE;
    192                 return exponent < 0 ? 0.0l : HUGE_VALL;
    193         }
    194        
    195         if (exponent < 0) {
    196                 exponent = -exponent;
    197                 for (int i = 0; i < 14; ++i) {
    198                         if (((exponent >> i) & 1) != 0) {
    199                                 base /= pow2[i];
    200                                 if (out_of_range(base)) {
     196                return exp < 0 ? LDBL_MIN : HUGE_VALL;
     197        }
     198       
     199        if (exp < 0) {
     200                exp = abs(exp);
     201                for (int i = 0; i <= MAX_POW2; ++i) {
     202                        if (((exp >> i) & 1) != 0) {
     203                                mant /= pow2[i];
     204                                if (mant == 0.0l) {
     205                                        mant = LDBL_MIN;
    201206                                        errno = ERANGE;
    202207                                        break;
     
    205210                }
    206211        } else {
    207                 for (int i = 0; i < 14; ++i) {
    208                         if (((exponent >> i) & 1) != 0) {
    209                                 base *= pow2[i];
    210                                 if (out_of_range(base)) {
     212                for (int i = 0; i <= MAX_POW2; ++i) {
     213                        if (((exp >> i) & 1) != 0) {
     214                                mant *= pow2[i];
     215                                if (mant == HUGE_VALL) {
    211216                                        errno = ERANGE;
    212217                                        break;
     
    216221        }
    217222       
    218         return base;
    219 }
     223        return mant;
     224}
     225
     226/* end power functions ********************************************************/
     227
     228
    220229
    221230/**
     
    231240static long double parse_decimal(const char **sptr)
    232241{
    233         // TODO: Use strtol(), at least for exponent.
     242        assert(sptr != NULL);
     243        assert (*sptr != NULL);
    234244       
    235245        const int DEC_BASE = 10;
    236246        const char DECIMAL_POINT = '.';
    237247        const char EXPONENT_MARK = 'e';
    238         /* The highest amount of digits that can be safely parsed
    239          * before an overflow occurs.
    240          */
    241         const int PARSE_DECIMAL_DIGS = 19;
    242        
    243         /* significand */
    244         uint64_t significand = 0;
    245        
    246         /* position in the input string */
    247         int i = 0;
     248       
     249        const char *str = *sptr;
     250        long double significand = 0;
     251        long exponent = 0;
    248252       
    249253        /* number of digits parsed so far */
    250254        int parsed_digits = 0;
    251        
    252         int exponent = 0;
    253        
    254         const char *str = *sptr;
    255        
    256         /* digits before decimal point */
    257         while (isdigit(str[i])) {
    258                 if (parsed_digits == 0 && str[i] == '0') {
     255        bool after_decimal = false;
     256       
     257        while (isdigit(*str) || (!after_decimal && *str == DECIMAL_POINT)) {
     258                if (*str == DECIMAL_POINT) {
     259                        after_decimal = true;
     260                        str++;
     261                        continue;
     262                }
     263               
     264                if (parsed_digits == 0 && *str == '0') {
    259265                        /* Nothing, just skip leading zeros. */
    260                 } else if (parsed_digits < PARSE_DECIMAL_DIGS) {
    261                         significand *= DEC_BASE;
    262                         significand += str[i] - '0';
     266                } else if (parsed_digits < LDBL_DIG) {
     267                        significand = significand * DEC_BASE + (*str - '0');
    263268                        parsed_digits++;
    264269                } else {
     
    266271                }
    267272               
    268                 i++;
    269         }
    270        
    271         if (str[i] == DECIMAL_POINT) {
    272                 i++;
    273                
    274                 /* digits after decimal point */
    275                 while (isdigit(str[i])) {
    276                         if (parsed_digits == 0 && str[i] == '0') {
    277                                 /* Skip leading zeros and decrement exponent. */
    278                                 exponent--;
    279                         } else if (parsed_digits < PARSE_DECIMAL_DIGS) {
    280                                 significand *= DEC_BASE;
    281                                 significand += str[i] - '0';
    282                                 exponent--;
    283                                 parsed_digits++;
    284                         } else {
    285                                 /* ignore */
    286                         }
    287                        
    288                         i++;
    289                 }
     273                if (after_decimal) {
     274                        /* Decrement exponent if we are parsing the fractional part. */
     275                        exponent--;
     276                }
     277               
     278                str++;
    290279        }
    291280       
    292281        /* exponent */
    293         if (tolower(str[i]) == EXPONENT_MARK) {
    294                 i++;
    295                
    296                 bool negative = false;
    297                 int exp = 0;
    298                
    299                 switch (str[i]) {
    300                 case '-':
    301                         negative = true;
    302                         /* fallthrough */
    303                 case '+':
    304                         i++;
    305                 }
    306                
    307                 while (isdigit(str[i])) {
    308                         if (exp < 65536) {
    309                                 exp *= DEC_BASE;
    310                                 exp += str[i] - '0';
    311                         }
    312                        
    313                         i++;
    314                 }
    315                
    316                 if (negative) {
    317                         exp = -exp;
    318                 }
    319                
    320                 exponent += exp;
    321         }
    322        
    323         long double result = (long double) significand;
    324         result = mul_pow5(result, exponent);
    325         if (result != HUGE_VALL) {
    326                 result = mul_pow2(result, exponent);
    327         }
    328        
    329         *sptr = &str[i];
    330         return result;
     282        if (tolower(*str) == EXPONENT_MARK) {
     283                str++;
     284               
     285                /* Returns MIN/MAX value on error, which is ok. */
     286                long exp = strtol(str, (char **) &str, DEC_BASE);
     287               
     288                if (exponent > 0 && exp > LONG_MAX - exponent) {
     289                        exponent = LONG_MAX;
     290                } else if (exponent < 0 && exp < LONG_MIN - exponent) {
     291                        exponent = LONG_MIN;
     292                } else {
     293                        exponent += exp;
     294                }
     295        }
     296       
     297        *sptr = str;
     298       
     299        /* Return multiplied by a power of ten. */
     300        return mul_pow2(mul_pow5(significand, exponent), exponent);
    331301}
    332302
     
    347317
    348318/**
    349  * Get the count of leading zero bits up to the maximum of 3 zero bits.
    350  *
    351  * @param val Integer value.
    352  * @return How many leading zero bits there are. (Maximum is 3)
    353  */
    354 static inline int leading_zeros(uint64_t val)
    355 {
    356         for (int i = 3; i > 0; --i) {
    357                 if ((val >> (64 - i)) == 0) {
    358                         return i;
    359                 }
    360         }
    361        
    362         return 0;
    363 }
    364 
    365 /**
    366319 * Convert hexadecimal string representation of the floating point number.
    367320 * Function expects the string pointer to be already pointed at the first
     
    376329static long double parse_hexadecimal(const char **sptr)
    377330{
    378         // TODO: Use strtol(), at least for exponent.
    379        
    380         /* this function currently always rounds to zero */
    381         // TODO: honor rounding mode
     331        assert(sptr != NULL && *sptr != NULL);
    382332       
    383333        const int DEC_BASE = 10;
     
    385335        const char DECIMAL_POINT = '.';
    386336        const char EXPONENT_MARK = 'p';
    387         /* The highest amount of digits that can be safely parsed
    388          * before an overflow occurs.
    389          */
    390         const int PARSE_HEX_DIGS = 16;
    391        
    392         /* significand */
    393         uint64_t significand = 0;
    394        
    395         /* position in the input string */
    396         int i = 0;
    397        
    398         /* number of digits parsed so far */
    399         int parsed_digits = 0;
    400        
    401         int exponent = 0;
    402337       
    403338        const char *str = *sptr;
    404        
    405         /* digits before decimal point */
    406         while (posix_isxdigit(str[i])) {
    407                 if (parsed_digits == 0 && str[i] == '0') {
     339        long double significand = 0;
     340        long exponent = 0;
     341       
     342        /* number of bits parsed so far */
     343        int parsed_bits = 0;
     344        bool after_decimal = false;
     345       
     346        while (posix_isxdigit(*str) || (!after_decimal && *str == DECIMAL_POINT)) {
     347                if (*str == DECIMAL_POINT) {
     348                        after_decimal = true;
     349                        str++;
     350                        continue;
     351                }
     352               
     353                if (parsed_bits == 0 && *str == '0') {
    408354                        /* Nothing, just skip leading zeros. */
    409                 } else if (parsed_digits < PARSE_HEX_DIGS) {
    410                         significand *= HEX_BASE;
    411                         significand += hex_value(str[i]);
    412                         parsed_digits++;
    413                 } else if (parsed_digits == PARSE_HEX_DIGS) {
    414                         /* The first digit may have had leading zeros,
    415                          * so we need to parse one more digit and shift
    416                          * the value accordingly.
    417                          */
    418                        
    419                         int zeros = leading_zeros(significand);
    420                         significand = (significand << zeros) |
    421                             (hex_value(str[i]) >> (4 - zeros));
    422                        
    423                         exponent += (4 - zeros);
    424                         parsed_digits++;
     355                } else if (parsed_bits <= LDBL_MANT_DIG) {
     356                        significand = significand * HEX_BASE + hex_value(*str);
     357                        parsed_bits += 4;
    425358                } else {
    426359                        exponent += 4;
    427360                }
    428361               
    429                 i++;
    430         }
    431        
    432         if (str[i] == DECIMAL_POINT) {
    433                 i++;
    434                
    435                 /* digits after decimal point */
    436                 while (posix_isxdigit(str[i])) {
    437                         if (parsed_digits == 0 && str[i] == '0') {
    438                                 /* Skip leading zeros and decrement exponent. */
    439                                 exponent -= 4;
    440                         } else if (parsed_digits < PARSE_HEX_DIGS) {
    441                                 significand *= HEX_BASE;
    442                                 significand += hex_value(str[i]);
    443                                 exponent -= 4;
    444                                 parsed_digits++;
    445                         } else if (parsed_digits == PARSE_HEX_DIGS) {
    446                                 /* The first digit may have had leading zeros,
    447                                  * so we need to parse one more digit and shift
    448                                  * the value accordingly.
    449                                  */
    450                                
    451                                 int zeros = leading_zeros(significand);
    452                                 significand = (significand << zeros) |
    453                                     (hex_value(str[i]) >> (4 - zeros));
    454                                
    455                                 exponent -= zeros;
    456                                 parsed_digits++;
    457                         } else {
    458                                 /* ignore */
    459                         }
    460                        
    461                         i++;
    462                 }
     362                if (after_decimal) {
     363                        exponent -= 4;
     364                }
     365               
     366                str++;
    463367        }
    464368       
    465369        /* exponent */
    466         if (tolower(str[i]) == EXPONENT_MARK) {
    467                 i++;
    468                
    469                 bool negative = false;
    470                 int exp = 0;
    471                
    472                 switch (str[i]) {
    473                 case '-':
    474                         negative = true;
    475                         /* fallthrough */
    476                 case '+':
    477                         i++;
    478                 }
    479                
    480                 while (isdigit(str[i])) {
    481                         if (exp < 65536) {
    482                                 exp *= DEC_BASE;
    483                                 exp += str[i] - '0';
    484                         }
    485                        
    486                         i++;
    487                 }
    488                
    489                 if (negative) {
    490                         exp = -exp;
    491                 }
    492                
    493                 exponent += exp;
    494         }
    495        
    496         long double result = (long double) significand;
    497         result = mul_pow2(result, exponent);
    498        
    499         *sptr = &str[i];
    500         return result;
     370        if (tolower(*str) == EXPONENT_MARK) {
     371                str++;
     372               
     373                /* Returns MIN/MAX value on error, which is ok. */
     374                long exp = strtol(str, (char **) &str, DEC_BASE);
     375               
     376                if (exponent > 0 && exp > LONG_MAX - exponent) {
     377                        exponent = LONG_MAX;
     378                } else if (exponent < 0 && exp < LONG_MIN - exponent) {
     379                        exponent = LONG_MIN;
     380                } else {
     381                        exponent += exp;
     382                }
     383        }
     384       
     385        *sptr = str;
     386       
     387        /* Return multiplied by a power of two. */
     388        return mul_pow2(significand, exponent);
    501389}
    502390
Note: See TracChangeset for help on using the changeset viewer.