The extension point for formatting numeric strings is through the IFormatProvider and ICustomFormatter interfaces. I implemented a format provider for the engineering notation. However, exclusively using engineering notation was awkward in our application. As an alternative to exclusively using engineering notation, I decided on the following format, which mixes four significant digits, engineering notation, and thousand separators:
3.1416E-05 31.42E-06 0.00031416 314.2E-06 0.0031416 0.003142 0.031416 0.03142 0.31416 0.3142 3.1416 3.142 31.416 31.42 314.16 314.2 3141.6 3,142 31416 31,416 3.1416E+05 314,159 3.1416E+06 3.142E+06 3.1416E+07 31.42E+06 3.1416E+08 314.2E+06 3.1416E+09 3.142E+09
In case you want similar formatting, here is the class that implements it:
public class EngineeringFormatProvider : IFormatProvider, ICustomFormatter { public object GetFormat(Type formatType) { return (formatType == typeof(ICustomFormatter)) ? this : null; } public string Format(string format, object arg, IFormatProvider formatProvider) { // for doubles, store the value of the double var val = Double.NaN; if (arg is Double) val = (double)arg; // for other types, try to convert to a double else { var typeConverter = TypeDescriptor.GetConverter(arg); if (typeConverter.CanConvertTo(typeof(Double))) { try { val = (double)typeConverter.ConvertTo(arg, typeof(Double)); } catch { // ignore } } // if cannot convert, return a default value if(Double.IsNaN(val)) return arg == null ? String.Empty : arg.ToString(); } // for special cases, just write out the string if (val == 0.0 || Double.IsNaN(val) || Double.IsInfinity(val)) return val.ToString(); else { // calculate the exponents, as a power of 3 var exp = Math.Log10(Math.Abs(val)); var exp3 = (int)(Math.Floor(exp / 3.0) * 3.0); // calculate the coefficient var coef = val / Math.Pow(10, exp3); // special case, for example 0.3142 if(exp3 == -3 && Math.Abs(coef / 1000.0) < 1 && Math.Abs(coef / 1000.0) > 0.1) return String.Format("{0:G4}", val); // for "small" numbers if(exp3 <= -6) return String.Format("{0:G4}E{1}{2:00}", coef, exp3 > 0 ? "+" : "", exp3); // for "large" numbers if(exp >= 6) return String.Format("{0:G4}E{1}{2:00}", coef, exp3 > 0 ? "+" : "", exp3); // for numbers needing thousand separators if (exp >= 3) return String.Format("{0:N0}", val); // default return String.Format("{0:G4}", val); } } }
Here is how to use it:
var p = new EngineeringFormatProvider(); var s = String.Format(p, "{0}", number);
No comments:
Post a Comment