home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 January / Chip_2001-01_cd1.bin / tema / mysql / mysql-3.23.28g-win-source.exe / strings / atof.c next >
C/C++ Source or Header  |  2000-08-31  |  5KB  |  209 lines

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.    
  3.    This library is free software; you can redistribute it and/or
  4.    modify it under the terms of the GNU Library General Public
  5.    License as published by the Free Software Foundation; either
  6.    version 2 of the License, or (at your option) any later version.
  7.    
  8.    This library is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11.    Library General Public License for more details.
  12.    
  13.    You should have received a copy of the GNU Library General Public
  14.    License along with this library; if not, write to the Free
  15.    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  16.    MA 02111-1307, USA */
  17.  
  18. /*
  19.   A quicker atof. About 2-10 times faster than standard atof on sparc.
  20.   This don't handle iee-options (NaN...) and the presission :s is a little
  21.   less for some high exponential numbers (+-1 at 14th place).
  22.   Returns 0.0 if overflow or wrong number.
  23.   Must be inited with init_my_atof to handle possibly overflows.
  24. */
  25.  
  26. #include <global.h>
  27. #ifdef USE_MY_ATOF                /* Skipp if we don't want it */
  28. #include <m_ctype.h>
  29. #include <floatingpoint.h>
  30. #include <signal.h>
  31.  
  32. /* Read a double. If float is wrong return 0.
  33.    float ::= [space]* [sign] {digit}+  decimal-point {digit}+ [exponent] |
  34.    [sign] {digit}+  [decimal-point {digit}*] exponent |
  35.    [sign] {digit}+  decimal-point [{digit}*] exponent |
  36.    [sign] decimal-point {digit}* exponent |
  37.    exponent :: = exponent-marker [sign] {digit}+
  38.    exponent-marker ::= E e
  39.    */
  40.  
  41.  
  42. #define is_exponent_marker(ch) (ch == 'E' || ch == 'e')
  43.  
  44. static void my_atof_overflow  _A((int sig,int code, struct sigcontext *scp,
  45.                   char *addr));
  46. static int parse_sign _A((char **str));
  47. static void parse_float_number_part _A((char **str,double *number, int *length));
  48. static void parse_decimal_number_part _A((char **str,double *number));
  49. static int parse_int_number_part _A((char **str,uint *number));
  50.  
  51. static int volatile overflow,in_my_atof;
  52. static sigfpe_handler_type old_overflow_handler;
  53.  
  54. void init_my_atof()
  55. {
  56.   old_overflow_handler = (sigfpe_handler_type)
  57.     ieee_handler("get", "overflow", old_overflow_handler);
  58.   VOID(ieee_handler("set", "overflow", my_atof_overflow));
  59.   return;
  60. }
  61.  
  62. static void my_atof_overflow(sig, code, scp, addr)
  63. int sig;
  64. int code;
  65. struct sigcontext *scp;
  66. char *addr;
  67. {
  68.   if (!in_my_atof)
  69.     old_overflow_handler(sig,code,scp,addr);
  70.   else
  71.     overflow=1;
  72.   return;
  73. }
  74.  
  75. double my_atof(src)
  76. const char *src;
  77. {
  78.   int        sign, exp_sign; /* is number negative (+1) or positive (-1) */
  79.   int        length_before_point;
  80.   double    after_point;    /* Number after decimal point and before exp */
  81.   uint        exponent;    /* Exponent value */
  82.   double    exp_log,exp_val;
  83.   char        *tmp_src;
  84.   double    result_number;
  85.  
  86.   tmp_src = (char*) src;
  87.   while (isspace(tmp_src[0]))
  88.     tmp_src++;                    /* Skipp pre-space */
  89.   sign = parse_sign(&tmp_src);
  90.   overflow=0;
  91.   in_my_atof=1;
  92.   parse_float_number_part(&tmp_src, &result_number, &length_before_point);
  93.   if (*tmp_src == '.')
  94.   {
  95.     tmp_src++;
  96.     parse_decimal_number_part(&tmp_src, &after_point);
  97.     result_number += after_point;
  98.   }
  99.   else if (length_before_point == 0)
  100.   {
  101.     in_my_atof=0;
  102.     return 0.0;
  103.   }
  104.   if (is_exponent_marker(*tmp_src))
  105.   {
  106.     tmp_src++;
  107.     exp_sign = parse_sign(&tmp_src);
  108.     overflow|=parse_int_number_part(&tmp_src, &exponent);
  109.  
  110.     exp_log=10.0; exp_val=1.0;
  111.     for (;;)
  112.     {
  113.       if (exponent & 1)
  114.       {
  115.     exp_val*= exp_log;
  116.     exponent--;
  117.       }
  118.       if (!exponent)
  119.     break;
  120.       exp_log*=exp_log;
  121.       exponent>>=1;
  122.     }
  123.     if (exp_sign < 0)
  124.       result_number*=exp_val;
  125.     else
  126.       result_number/=exp_val;
  127.   }
  128.   if (sign > 0)
  129.     result_number= -result_number;
  130.  
  131.   in_my_atof=0;
  132.   if (overflow)
  133.     return 0.0;
  134.   return result_number;
  135. }
  136.  
  137.  
  138. static int parse_sign(str)
  139. char **str;
  140. {
  141.   if (**str == '-')
  142.   {
  143.     (*str)++;
  144.     return 1;
  145.   }
  146.   if (**str == '+')
  147.     (*str)++;
  148.   return -1;
  149. }
  150.  
  151.     /* Get number with may be separated with ',' */
  152.  
  153. static void parse_float_number_part(str, number, length)
  154. char **str;
  155. double *number;
  156. int *length;
  157. {
  158.   *number = 0;
  159.   *length = 0;
  160.  
  161.   for (;;)
  162.   {
  163.     while (isdigit(**str))
  164.     {
  165.       (*length)++;
  166.       *number = (*number * 10) + (**str - '0');
  167.       (*str)++;
  168.     }
  169.     if (**str != ',')
  170.       return;                    /* Skipp possibly ',' */
  171.     (*str)++;
  172.   }
  173. }
  174.  
  175. static void parse_decimal_number_part(str, number)
  176. char **str;
  177. double *number;
  178. {
  179.   double exp_log;
  180.  
  181.   *number = 0;
  182.   exp_log=1/10.0;
  183.   while (isdigit(**str))
  184.   {
  185.     *number+= (**str - '0')*exp_log;
  186.     exp_log/=10;
  187.     (*str)++;
  188.   }
  189. }
  190.  
  191.     /* Parses int suitably for exponent */
  192.  
  193. static int parse_int_number_part(str, number)
  194. char **str;
  195. uint *number;
  196. {
  197.   *number = 0;
  198.   while (isdigit(**str))
  199.   {
  200.     if (*number >= ((uint) ~0)/10)
  201.       return 1;                        /* Don't overflow */
  202.     *number = (*number * 10) + **str - '0';
  203.     (*str)++;
  204.   }
  205.   return 0;
  206. }
  207.  
  208. #endif
  209.