00001 /******************************************************************************* 00002 00003 @file DGDouble.d 00004 00005 Copyright (c) 2004 Kris Bell 00006 00007 This software is provided 'as-is', without any express or implied 00008 warranty. In no event will the authors be held liable for damages 00009 of any kind arising from the use of this software. 00010 00011 Permission is hereby granted to anyone to use this software for any 00012 purpose, including commercial applications, and to alter it and/or 00013 redistribute it freely, subject to the following restrictions: 00014 00015 1. The origin of this software must not be misrepresented; you must 00016 not claim that you wrote the original software. If you use this 00017 software in a product, an acknowledgment within documentation of 00018 said product would be appreciated but is not required. 00019 00020 2. Altered source versions must be plainly marked as such, and must 00021 not be misrepresented as being the original software. 00022 00023 3. This notice may not be removed or altered from any distribution 00024 of the source. 00025 00026 4. Derivative works are permitted, but they must carry this notice 00027 in full and credit the original source. 00028 00029 00030 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00031 00032 00033 @version Initial version, Feb 2005 00034 @author Kris 00035 00036 00037 *******************************************************************************/ 00038 00039 module mango.format.DGDouble; 00040 00041 private import mango.format.Number; 00042 00043 /******************************************************************************* 00044 00045 Callback for dtoa allocation function 00046 00047 *******************************************************************************/ 00048 00049 extern (C) 00050 { 00051 void* __dToaMalloc (uint size) 00052 { 00053 throw new Exception ("unexpected memory request from DGDouble"); 00054 return new byte[2048]; 00055 } 00056 00057 char* dtoa (double d, int mode, int ndigits, int* decpt, int* sign, char** rve); 00058 double atod (char* s00, int len, char** se); 00059 } 00060 00061 00062 /****************************************************************************** 00063 00064 David Gay's extended conversions between string and floating-point 00065 numeric representations. Use these where you need extended accuracy 00066 when converting. 00067 00068 Note that this class requires the attendent dtoa.c file to be 00069 compiled into the Mango library. 00070 00071 ******************************************************************************/ 00072 00073 class DGDouble : Number 00074 { 00075 /********************************************************************** 00076 00077 Convert a formatted string of digits to a floating- 00078 point number. 00079 00080 **********************************************************************/ 00081 00082 final static double parse (tChar[] src, uint* ate=null) 00083 { 00084 char* end; 00085 00086 double x = atod (src.ptr, src.length, &end); 00087 if (ate) 00088 *ate = end - src.ptr; 00089 return x; 00090 } 00091 00092 00093 /********************************************************************** 00094 00095 Convert a floating-point number to a string. Parameter 'mode' 00096 should be specified thusly: 00097 00098 0 ==> shortest string that yields d when read in 00099 and rounded to nearest. 00100 00101 1 ==> like 0, but with Steele & White stopping rule; 00102 e.g. with IEEE P754 arithmetic , mode 0 gives 00103 1e23 whereas mode 1 gives 9.999999999999999e22. 00104 00105 2 ==> max(1,ndigits) significant digits. This gives a 00106 return value similar to that of ecvt, except 00107 that trailing zeros are suppressed. 00108 00109 3 ==> through ndigits past the decimal point. This 00110 gives a return value similar to that from fcvt, 00111 except that trailing zeros are suppressed, and 00112 ndigits can be negative. 00113 00114 4,5 ==> similar to 2 and 3, respectively, but (in 00115 round-nearest mode) with the tests of mode 0 to 00116 possibly return a shorter string that rounds to d. 00117 With IEEE arithmetic and compilation with 00118 -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same 00119 as modes 2 and 3 when FLT_ROUNDS != 1. 00120 00121 6-9 ==> Debugging modes similar to mode - 4: don't try 00122 fast floating-point estimate (if applicable). 00123 00124 **********************************************************************/ 00125 00126 static final tChar[] format (tChar[] dst, double x, uint decimals = 6, bool scientific = false, uint mode=3) 00127 in { 00128 assert (dst.length >= 32); 00129 } 00130 body 00131 { 00132 char* end, 00133 str; 00134 int sign, 00135 decpt; 00136 00137 str = dtoa (x, mode, decimals, &decpt, &sign, &end); 00138 00139 char *p = dst; 00140 int len = end - str; 00141 00142 if (sign) 00143 *p++ = '-'; 00144 00145 if (decpt == 9999) 00146 p[0..len] = str[0..len]; 00147 else 00148 { 00149 int exp = decpt - 1; 00150 sign = 0; 00151 if (exp < 0) 00152 { 00153 exp = -exp; 00154 sign = 1; 00155 } 00156 00157 // force scientific format if too long ... 00158 if ((exp + len + 2) > dst.length) 00159 scientific = true; 00160 00161 if (scientific) 00162 { 00163 *p++ = *str++; 00164 *p++ = '.'; 00165 while (str < end) 00166 *p++ = *str++; 00167 *p++ = 'e'; 00168 *p++ = (sign) ? '-' : '+'; 00169 00170 if (exp >= 100) 00171 { 00172 *p++ = exp / 100 + '0'; 00173 exp %= 100; 00174 } 00175 *p++ = exp / 10 + '0'; 00176 *p++ = exp % 10 + '0'; 00177 } 00178 else 00179 { 00180 if (decpt <= 0) 00181 *p++ = '0'; 00182 else 00183 { 00184 while (decpt > 0) 00185 { 00186 *p++ = (str < end) ? *str++ : '0'; 00187 --decpt; 00188 } 00189 } 00190 if (str < end) 00191 { 00192 *p++ = '.'; 00193 while (decpt < 0) 00194 { 00195 *p++ = '0'; 00196 ++decpt; 00197 } 00198 while (str < end) 00199 *p++ = *str++; 00200 } 00201 } 00202 } 00203 00204 return dst[0..(p - dst.ptr)]; 00205 } 00206 } 00207 00208