001package ca.bc.webarts.widgets; 002 003import java.io.*; 004import java.util.*; 005import java.math.*; 006import java.net.*; 007import java.text.*; 008 009/** 010 * This code formats numbers in Scientific Notation. The input Number object is returned 011 * as a ScientificFormated string. There are two output styles: Pure and Standard scientific 012 * notation. Pure formatted numbers have precisely the number of digits specified by the 013 * significant digits (sigDig) parameter and always specify a Base 10 Exponential(E). 014 * Standard formated numbers have the number of digits specified by the significant 015 * digits (sigDig) parameter but will not have a Base 10 Exponential(E) if the number of digits 016 * in the mantissa <= maxWidth. 017 * 018 * @author Paul Spence 019 * @version 03/20/2000 020 */ 021 022public class ScientificFormat extends Format 023{ 024 /** 025 * The number of significant digits the number is formatted to is recorded by sigDigit. 026 * The maximum width allowed fro the returned String is recorded by MaxWidth 027 */ 028 private int sigDigit = 5; 029 private int maxWidth = 8; 030 private boolean SciNote = false; //set to true for pure Scientific Notation 031 032 public ScientificFormat() { 033 034 } 035 036 /** 037 * Sets the significant digits, maximum allowable width and number formatting style 038 * (SciNote == true for Pure formatting). 039 */ 040 public ScientificFormat(int sigDigit, int maxWidth, boolean SciNote) 041 { 042 setSigDigits(sigDigit); 043 setMaxWidth(maxWidth); 044 setScientificNotationStyle(SciNote); 045 } 046 047 /** 048 * Implementation of inherited abstract method. Checks to see if object to be formatted 049 * is of type Number. If so casts the Number object to double and calls the format method. 050 * Returns the result. 051 */ 052 public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) 053 { 054 if (obj instanceof Number) 055 { 056 String result = format(((Number) obj).doubleValue()); 057 return toAppendTo.append(result); 058 } 059 else if (obj instanceof DoubleWithError) 060 { 061 DoubleWithError dwe = (DoubleWithError) obj; 062 toAppendTo.append(format(dwe.getValue())); 063 toAppendTo.append(dwe.plusorminus); 064 int errorSigDigit = resolveErrorSigDigit(dwe.getValue(),dwe.getError()); 065 toAppendTo.append(formatError(errorSigDigit,dwe.getError())); 066 return toAppendTo; 067 } 068 else throw new IllegalArgumentException("Cannot format given Object as a Number"); 069 } 070 071 /**Dummy implementation of inherited abstract method. 072 */ 073 public Object parseObject (String source, ParsePosition pos) 074 { 075 return null; 076 } 077 078 /** 079 * Returns the number of significant digits 080 */ 081 public int getSigDigits() 082 { 083 return sigDigit; 084 } 085 086 /** 087 * Returns the maximum allowable width of formatted number excluding any exponentials 088 */ 089 public int getMaxWidth() 090 { 091 return maxWidth; 092 } 093 094 /** 095 * Returns the formatting style: True means Pure scientific formatting, False means standard. 096 */ 097 public boolean getScientificNotationStyle() 098 { 099 return SciNote; 100 } 101 102 /** 103 * Sets the number of significant digits for the formatted number 104 */ 105 public void setSigDigits(int SigDigit) 106 { 107 if (SigDigit < 1) throw new IllegalArgumentException ("sigDigit"); 108 sigDigit = SigDigit; 109 } 110 111 /** 112 * Sets the maximum allowable length of the formattted number mantissa before exponential notation 113 * is used. 114 */ 115 public void setMaxWidth(int mWidth) 116 { 117 if (mWidth < 3) throw new IllegalArgumentException ("maxWidth"); 118 maxWidth = mWidth; 119 } 120 /** 121 * Sets the format style used. 122 * There are two output styles: Pure and Standard scientific 123 * notation. Pure formatted numbers have precisely the number of digits specified by the 124 * significant digits (sigDig) parameter and always specify a Base 10 Exponential(E). 125 * Standard formated numbers have the number of digits specified by the significant 126 * digits (sigDig) parameter but will not have a Base 10 Exponential(E) if the number of digits 127 * in the mantissa <= maxWidth. 128 */ 129 public void setScientificNotationStyle(boolean sciNote) 130 { 131 SciNote = sciNote; 132 } 133 134 135 //simplify method for taking log base 10 of x 136 private final static double k = 1/Math.log(10); 137 private double Log10(double x) 138 { 139 if (x==0) return 0; 140 else return Math.log(x)*k; 141 } 142 143 private int resolveErrorSigDigit(double x, double dx){ 144 //dx should never be negative 145 dx = Math.abs(dx); 146 //make x +ve cause negative doesn't effect sigdigits 147 x=Math.abs(x); 148 149 //these circumstances errorsigdit does equal sigdigit, excluding infinity and Nan which are handled by format 150 if(dx == 0 || Double.isInfinite(dx) || Double.isNaN(dx) || dx >= x) return sigDigit; 151 152 //fail cases for log, method fails to handle 153 if(x==0||Double.isInfinite(x) || Double.isNaN(x))return sigDigit; 154 155 //other wise solve for cases when dx< x 156 int log =(int)Math.round(Log10(dx/x));//always will return negative number 157 int errorsigdigit = sigDigit+log; 158 if(errorsigdigit <1) return 1; 159 return errorsigdigit; 160 } 161 162 /** 163 * Format the number using scientific notation 164 */ 165 public String format(double d) 166 { 167 // Deal with a few special values first 168 if (Double.isInfinite(d)) return maxWidth < 8 ? "INF" : "Infinite"; 169 if (Double.isNaN(d)) return "NaN"; 170 171 String result=""; 172 double c=0; 173 int ShiftNumber = 0; 174 int IntOfNumberinput = 0; 175 176 //preserve sign 177 if (d==0) return "0"; 178 else { 179 c=d; 180 d=Math.abs(c); 181 } 182 183 // (i.e. 10 -> 1, 100 -> 2,9 -> 0 , .9 -> -1, .0009 -> -4) 184 //error here 10 -> 1.0000 floors to 0 185 IntOfNumberinput = (int) Math.floor(Log10(d));//returns largest int value that is smaller than log10(d) 186 187 //deal with above error 188 if((IntOfNumberinput>-1)&&(d%(Math.pow(10,IntOfNumberinput+1)) == 0)){ 189 IntOfNumberinput++; 190 } 191 192 193 //if 0<d<1 then log10(d)is neg, IntofNumberinput is negative 194 if (Log10(d)<0){ 195 ShiftNumber = sigDigit - IntOfNumberinput - 1; 196 }else { 197 ShiftNumber = sigDigit - IntOfNumberinput; 198 } 199 200 201 //outputs num with all sigdigs to right of decimal place or rounded up one extra 202 long temp = Math.round(Math.pow(10,ShiftNumber)*d); 203 String Formatted = String.valueOf(temp); 204 205 //check rounding method, if neccessary add 1 to IntOfNumberinput 206 BigDecimal tempbunk =new BigDecimal(Math.pow(10,ShiftNumber)*d); 207 long bunk =tempbunk.longValue(); 208 String Formattedbunk = String.valueOf(bunk); 209 210 211 if(Formatted.length() > Formattedbunk.length()){ 212 IntOfNumberinput++; 213 } 214 215 216 //Do not display in pure sci notattion - limit use of E 217 if (SciNote == false) 218 { 219 if (IntOfNumberinput < 0 ) { 220 String LoopZero1=""; 221 for (int a=0; a<(Math.abs(IntOfNumberinput)-1);a++){ 222 LoopZero1=LoopZero1+"0"; 223 } 224 result="0"+"."+LoopZero1+Formatted; 225 226 } 227 228 else{ 229 String[] FillDigits = new String[IntOfNumberinput+1]; 230 for(int a=0;a<=IntOfNumberinput;a++){ 231 FillDigits[a]="0"; 232 } 233 234 int a = 0; 235 236 while((a < Formatted.length()) && a<=IntOfNumberinput){ 237 FillDigits[a] = Formatted.substring(a,a+1); 238 a++; 239 } 240 241 for(int i=0; i <= FillDigits.length-1 ; i++){ 242 result = result + FillDigits[i]; 243 } 244 245 int length = result.length(); 246 247 248 if(length <sigDigit){ 249 String resultaddon =""; 250 int i=-1; 251 if(IntOfNumberinput==0){ 252 while(length < sigDigit){ 253 resultaddon = resultaddon + Formatted.substring(result.length()+i+1,result.length()+i+2); 254 length++; 255 i++; 256 } 257 }else{ 258 i = 0; 259 while(length < sigDigit){ 260 resultaddon = resultaddon + Formatted.substring(result.length()+i,result.length()+i+1); 261 length++; 262 i++; 263 } 264 } 265 266 result = result+"."+resultaddon; 267 } 268 } 269 270 271 if(result.length()>maxWidth){ 272 result=Formatted.substring(0,1)+"."+Formatted.substring(1,sigDigit)+"E"+IntOfNumberinput; 273 } 274 } 275 276 //output in pure Scientific Notation 277 if(SciNote == true){ 278 result=Formatted.substring(0,1)+"."+Formatted.substring(1,sigDigit)+"E"+IntOfNumberinput; 279 } 280 281 //regain negative and return 282 if(c>0) return result; 283 else return "-"+result; 284 285 286 } 287 /** 288 * Format the number using scientific notation 289 */ 290 public String formatError(int eSD,double d) 291 { 292 // Deal with a few special values first 293 if (Double.isInfinite(d)) return maxWidth < 8 ? "INF" : "Infinite"; 294 if (Double.isNaN(d)) return "NaN"; 295 296 int errorSigDigit = eSD; 297 298 String result=""; 299 double c=0; 300 int ShiftNumber = 0; 301 int IntOfNumberinput = 0; 302 303 //preserve sign 304 if (d==0) return "0"; 305 else { 306 c=d; 307 d=Math.abs(c); 308 } 309 310 // (i.e. 10 -> 1, 100 -> 2,9 -> 0 , .9 -> -1, .0009 -> -4) 311 //error here 10 -> 1.0000 floors to 0 312 IntOfNumberinput = (int) Math.floor(Log10(d));//returns largest int value that is smaller than log10(d) 313 314 //deal with above error 315 if((IntOfNumberinput>-1)&&(d%(Math.pow(10,IntOfNumberinput+1)) == 0)){ 316 IntOfNumberinput++; 317 } 318 319 320 //if 0<d<1 then log10(d)is neg, IntofNumberinput is negative 321 if (Log10(d)<0){ 322 ShiftNumber = errorSigDigit - IntOfNumberinput - 1; 323 }else { 324 ShiftNumber = errorSigDigit - IntOfNumberinput; 325 } 326 327 328 //outputs num with all sigdigs to right of decimal place or rounded up one extra 329 long temp = Math.round(Math.pow(10,ShiftNumber)*d); 330 String Formatted = String.valueOf(temp); 331 332 //check rounding method, if neccessary add 1 to IntOfNumberinput 333 BigDecimal tempbunk =new BigDecimal(Math.pow(10,ShiftNumber)*d); 334 long bunk =tempbunk.longValue(); 335 String Formattedbunk = String.valueOf(bunk); 336 337 338 if(Formatted.length() > Formattedbunk.length()){ 339 IntOfNumberinput++; 340 } 341 342 343 //Do not display in pure sci notattion - limit use of E 344 if (SciNote == false) 345 { 346 if (IntOfNumberinput < 0 ) { 347 String LoopZero1=""; 348 for (int a=0; a<(Math.abs(IntOfNumberinput)-1);a++){ 349 LoopZero1=LoopZero1+"0"; 350 } 351 result="0"+"."+LoopZero1+Formatted; 352 353 } 354 355 else{ 356 String[] FillDigits = new String[IntOfNumberinput+1]; 357 for(int a=0;a<=IntOfNumberinput;a++){ 358 FillDigits[a]="0"; 359 } 360 361 int a = 0; 362 363 while((a < Formatted.length()) && a<=IntOfNumberinput){ 364 FillDigits[a] = Formatted.substring(a,a+1); 365 a++; 366 } 367 368 for(int i=0; i <= FillDigits.length-1 ; i++){ 369 result = result + FillDigits[i]; 370 } 371 372 int length = result.length(); 373 374 375 if(length <errorSigDigit){ 376 String resultaddon =""; 377 int i=-1; 378 if(IntOfNumberinput==0){ 379 while(length < errorSigDigit){ 380 resultaddon = resultaddon + Formatted.substring(result.length()+i+1,result.length()+i+2); 381 length++; 382 i++; 383 } 384 }else{ 385 i = 0; 386 while(length < errorSigDigit){ 387 resultaddon = resultaddon + Formatted.substring(result.length()+i,result.length()+i+1); 388 length++; 389 i++; 390 } 391 } 392 393 result = result+"."+resultaddon; 394 } 395 } 396 397 398 if(result.length()>maxWidth){ 399 result=Formatted.substring(0,1)+"."+Formatted.substring(1,errorSigDigit)+"E"+IntOfNumberinput; 400 } 401 } 402 403 //output in pure Scientific Notation 404 if(SciNote == true){ 405 result=Formatted.substring(0,1)+"."+Formatted.substring(1,errorSigDigit)+"E"+IntOfNumberinput; 406 } 407 408 //regain negative and return 409 if(c>0) return result; 410 else return "-"+result; 411 412 413 } 414 415}