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 00035 @author Kris 00036 00037 00038 *******************************************************************************/ 00039 00040 module mango.convert.DGDouble; 00041 00042 /******************************************************************************* 00043 00044 External requirements for this package 00045 00046 *******************************************************************************/ 00047 00048 extern (C) 00049 { 00050 // these should be linked in via dtoa.c 00051 char* dtoa (double d, int mode, int ndigits, int* decpt, int* sign, char** rve); 00052 double atod (char* s00, int len, char** se); 00053 00054 00055 // callback for dtoa allocation function 00056 void* __dToaMalloc (uint size) 00057 { 00058 throw new Exception ("unexpected memory request from DGDouble"); 00059 //return new byte[2048]; 00060 } 00061 } 00062 00063 00064 /****************************************************************************** 00065 00066 David Gay's extended conversions between string and floating-point 00067 numeric representations. Use these where you need extended accuracy 00068 for convertions. 00069 00070 Note that this class requires the attendent file dtoa.c be compiled 00071 and linked to the application. 00072 00073 While these functions are all static, they are encapsulated within 00074 a class inheritance to preserve some namespace cohesion. One might 00075 use structs for encapsualtion instead, but then inheritance would 00076 be lost. Note that the root class, Styled, is abstract to prevent 00077 accidental instantiation of these classes. 00078 00079 ******************************************************************************/ 00080 00081 struct DGDouble 00082 { 00083 /********************************************************************** 00084 00085 Convert a formatted string of digits to a floating- 00086 point number. 00087 00088 **********************************************************************/ 00089 00090 final static double parse (char[] src, uint* ate=null) 00091 { 00092 char* end; 00093 00094 double x = atod (src.ptr, src.length, &end); 00095 if (ate) 00096 *ate = end - src.ptr; 00097 return x; 00098 } 00099 00100 00101 /********************************************************************** 00102 00103 Signature for use with Format module 00104 00105 **********************************************************************/ 00106 00107 static final char[] format (char[] dst, double x, uint decimals, bool scientific) 00108 { 00109 return format (dst, x, decimals, scientific, 3); 00110 } 00111 00112 00113 /********************************************************************** 00114 00115 Convert a floating-point number to a string. Parameter 'mode' 00116 should be specified thusly: 00117 00118 0 ==> shortest string that yields d when read in 00119 and rounded to nearest. 00120 00121 1 ==> like 0, but with Steele & White stopping rule; 00122 e.g. with IEEE P754 arithmetic , mode 0 gives 00123 1e23 whereas mode 1 gives 9.999999999999999e22. 00124 00125 2 ==> max(1,ndigits) significant digits. This gives a 00126 return value similar to that of ecvt, except 00127 that trailing zeros are suppressed. 00128 00129 3 ==> through ndigits past the decimal point. This 00130 gives a return value similar to that from fcvt, 00131 except that trailing zeros are suppressed, and 00132 ndigits can be negative. 00133 00134 4,5 ==> similar to 2 and 3, respectively, but (in 00135 round-nearest mode) with the tests of mode 0 to 00136 possibly return a shorter string that rounds to d. 00137 With IEEE arithmetic and compilation with 00138 -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same 00139 as modes 2 and 3 when FLT_ROUNDS != 1. 00140 00141 6-9 ==> Debugging modes similar to mode - 4: don't try 00142 fast floating-point estimate (if applicable). 00143 00144 **********************************************************************/ 00145 00146 static final char[] format (char[] dst, double x, uint decimals = 6, bool scientific = false, uint mode=3) 00147 in { 00148 assert (dst.length >= 32); 00149 } 00150 body 00151 { 00152 char* end, 00153 str; 00154 int sign, 00155 decpt; 00156 00157 str = dtoa (x, mode, decimals, &decpt, &sign, &end); 00158 00159 char *p = dst; 00160 int len = end - str; 00161 00162 if (sign) 00163 *p++ = '-'; 00164 00165 if (decpt == 9999) 00166 p[0..len] = str[0..len]; 00167 else 00168 { 00169 int exp = decpt - 1; 00170 sign = 0; 00171 if (exp < 0) 00172 { 00173 exp = -exp; 00174 sign = 1; 00175 } 00176 00177 // force scientific format if too long ... 00178 if ((exp + len + 2) > dst.length) 00179 scientific = true; 00180 00181 if (scientific) 00182 { 00183 *p++ = *str++; 00184 *p++ = '.'; 00185 while (str < end) 00186 *p++ = *str++; 00187 *p++ = 'e'; 00188 *p++ = (sign) ? '-' : '+'; 00189 00190 if (exp >= 100) 00191 { 00192 *p++ = exp / 100 + '0'; 00193 exp %= 100; 00194 } 00195 *p++ = exp / 10 + '0'; 00196 *p++ = exp % 10 + '0'; 00197 } 00198 else 00199 { 00200 if (decpt <= 0) 00201 *p++ = '0'; 00202 else 00203 { 00204 while (decpt > 0) 00205 { 00206 *p++ = (str < end) ? *str++ : '0'; 00207 --decpt; 00208 } 00209 } 00210 if (str < end) 00211 { 00212 *p++ = '.'; 00213 while (decpt < 0) 00214 { 00215 *p++ = '0'; 00216 ++decpt; 00217 } 00218 while (str < end) 00219 *p++ = *str++; 00220 } 00221 } 00222 } 00223 00224 return dst[0..(p - dst.ptr)]; 00225 } 00226 } 00227 00228