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