Is there any code out there (or a built-in function) which allows outputting a floating point number in engineering notation?
For example, 1.5e-4 would be displayed as 150µ and 5e-3 would be displayed as 5m.
Is there any code out there (or a built-in function) which allows outputting a floating point number in engineering notation?
For example, 1.5e-4 would be displayed as 150µ and 5e-3 would be displayed as 5m.
This may need refactoring:
private static string ToEngineeringNotation(this double d)
{
double exponent = Math.Log10(Math.Abs(d));
if (Math.Abs(d) >= 1)
{
switch ((int)Math.Floor(exponent))
{
case 0: case 1: case 2:
return d.ToString();
case 3: case 4: case 5:
return (d / 1e3).ToString() + "k";
case 6: case 7: case 8:
return (d / 1e6).ToString() + "M";
case 9: case 10: case 11:
return (d / 1e9).ToString() + "G";
case 12: case 13: case 14:
return (d / 1e12).ToString() + "T";
case 15: case 16: case 17:
return (d / 1e15).ToString() + "P";
case 18: case 19: case 20:
return (d / 1e18).ToString() + "E";
case 21: case 22: case 23:
return (d / 1e21).ToString() + "Z";
default:
return (d / 1e24).ToString() + "Y";
}
}
else if (Math.Abs(d) > 0)
{
switch ((int)Math.Floor(exponent))
{
case -1: case -2: case -3:
return (d * 1e3).ToString() + "m";
case -4: case -5: case -6:
return (d * 1e6).ToString() + "μ";
case -7: case -8: case -9:
return (d * 1e9).ToString() + "n";
case -10: case -11: case -12:
return (d * 1e12).ToString() + "p";
case -13: case -14: case -15:
return (d * 1e15).ToString() + "f";
case -16: case -17: case -18:
return (d * 1e15).ToString() + "a";
case -19: case -20: case -21:
return (d * 1e15).ToString() + "z";
default:
return (d * 1e15).ToString() + "y";
}
}
else
{
return "0";
}
}
Here's a link to some Ruby code that does something similar, though it formats as dddem, where m, the exponent, is always a multiple of 3.
Transliteration to C#. Since I'm not familiar with the format I'm not sure this does exactly what you want. For example, 0.0015 formats as 2e-3. It would be reasonably trivial to substitute the Greek letters for the exponent using a case statement and UTF-8 or other encodings. The exercise is left to the reader.
public static class FormatExtensions
{
public static string ToEngineering( this double value )
{
int exp = (int)(Math.Floor( Math.Log10( value ) / 3.0 ) * 3.0);
double newValue = value * Math.Pow(10.0,-exp);
if (newValue >= 1000.0) {
newValue = newValue / 1000.0;
exp = exp + 3;
}
return string.Format( "{0:##0}e{1}", newValue, exp);
}
}
Usage:
Console.WriteLine( ((double)15000).ToEngineering() );
double val = 15000;
Console.WriteLine( val.ToEngineering() );
Rather than subclassing, I'd take advantage of the fact that Double implements IFormattable and write an IFormatProvider that formats the number. Then I'd have code that looks similar to:
double d = 123.45;
Console.WriteLine(d.ToString(null, new MyCustomFormat()));
Combining two of the earlier answers and adding a unit (volt, etc.) gives nice tidy answers like 11000 volts as 11kV.
public static string ToEngineering(this double value, string unitName)
{
int exp = (int)(Math.Floor(Math.Log10(value) / 3.0) * 3.0);
double newValue = value * Math.Pow(10.0, -exp);
if (newValue >= 1000.0)
{
newValue = newValue / 1000.0;
exp = exp + 3;
}
var symbol = String.Empty;
switch (exp)
{
case 3:
symbol = "k";
break;
case 6:
symbol = "M";
break;
case 9:
symbol = "G";
break;
case 12:
symbol = "T";
break;
case -3:
symbol = "m";
break;
case -6:
symbol = "μ";
break;
case -9:
symbol = "n";
break;
case -12:
symbol = "p";
break;
}
return string.Format("{0:##0.000} {1}{2}", newValue, symbol, unitName);
}
Here is another version that handles negative and without rounding
public static string ToEngineering(this double value)
{
var absValue = Math.Abs(value);
var exp = absValue < 0.001 ? 0 : (int)(Math.Floor(Math.Log10(absValue) / 3.0) * 3.0);
var newValue = value * Math.Pow(10.0, -exp);
return $"{newValue}e{exp}";
}
I came here looking for a function that can take any numeric representation e.g. signed/unsigned int, float, double, decimal, numeric string, and while I found some inspiration Patrick McDonald's answer, I didn't find the full answer I was looking for, so I wrote my own solution that takes a numeric string, which can be obtained easily from any numeric type. I am sharing my solution in this thread for others to use if they wish to have something more generic:
public static string ToEngineeringNotation(string originalString, int? significantFigures = null)
{
var str = originalString;
// remove spaces and negative sign
str.Replace(" ", "");
string prefix = "";
if (str[0] == '-')
{
str = str.Substring(1);
prefix = "-";
}
// Get the exponent, remove the exponent nomenclature
int exponent = 0;
int exponentStrIndex = 0;
if ((exponentStrIndex = str.IndexOfAny("Ee".ToArray())) >= 0)
{
string exponentStr = str.Substring(exponentStrIndex + 1);
str = str.Substring(0, exponentStrIndex);
Int32.TryParse(exponentStr, out exponent);
}
// remove the decimal point, and adjust the exponent so the decimal point
// should go just after the first digit, and trim trailing zeros
int currentDecimalPosition = str.IndexOf('.');
if (currentDecimalPosition >= 0)
{
exponent += currentDecimalPosition-1;
str = str.Replace(".", "");
}
else
{
exponent += str.Length - 1;
}
str = str.TrimEnd('0');
// At this point we should only have digits, just return the original string if we don't
if (!str.All(char.IsDigit))
{
return originalString;
}
// Trim leading zeros, the decimal point is effectively moved as it's
// just after the first digit, so adjust the exponent
int lengthBefore = str.Length;
str = str.TrimStart('0');
exponent += str.Length-lengthBefore;
// Put the decimal point back in, but move the decimal point right
// according to the shift worked out above.
if (significantFigures.HasValue && significantFigures.Value < str.Length)
{
if (str.Length >= significantFigures.Value && str[significantFigures.Value] >= '5' && Int64.TryParse(str.Substring(0, significantFigures.Value), out var integerValue))
{
// Need to round up
str = (integerValue + 1).ToString();
if(str.Length> significantFigures.Value)
{
++exponent;
}
}
str = str.Substring(0, significantFigures.Value);
}
// work out how much we need to shift the decimal point to get
// engineering notation
var decimalShiftRequired = exponent % 3;
if (decimalShiftRequired < 0)
decimalShiftRequired += 3;
if (exponent == 0)
{
decimalShiftRequired = 0;
}
str = str.PadRight(1 + decimalShiftRequired, '0');
str = $"{str.Substring(0, 1 + decimalShiftRequired)}.{str.Substring(1 + decimalShiftRequired)}";
exponent -= decimalShiftRequired;
// Remove the decimal point if there are no digits after it
str = str.TrimEnd('.');
// Create a default suffix consisting of the exponent
string suffix = exponent != 0 ? $"E{(exponent < 0 ? "" : "+")}{exponent}" : "";
// Work out which letter to put on the end, if any. If no letter is found,
// then the Exponent suffix above will be added without modification
switch (exponent)
{
case 3:
suffix = "k"; break;
case 6:
suffix = "M"; break;
case 9:
suffix = "G"; break;
case 12:
suffix = "T"; break;
case 15:
suffix = "P"; break;
case 18:
suffix = "E"; break;
case 21:
suffix = "Z"; break;
case 24:
suffix = "Y"; break;
case -3:
suffix = "m"; break;
case -6:
suffix = "μ"; break;
case -9:
suffix = "n"; break;
case -12:
suffix = "p"; break;
case -15:
suffix = "f"; break;
case -18:
suffix = "a"; break;
case -21:
suffix = "z"; break;
case -24:
suffix = "y"; break;
}
return $"{prefix}{str}{suffix}";
}
Here's the comment block that goes at the top of the above function, I've put it here at the end so people don't have to scroll through it to get to the code:
/// <summary>
/// Converts a numeric string to Engineering Notation
/// </summary>
/// <example>
/// class Program
/// {
/// static void Main(string[] args)
/// {
/// foreach(var a in SampleNumbers)
/// {
/// var leftPad = a < 0 ? "" : " ";
/// var rightPad = a < 0 ? "--> " : "-> ";
/// var original = $"{leftPad}{a.ToString().PadRight(22)}{rightPad}";
/// var engineering = $"{leftPad}{a.ToEngineeringNotation(256).PadRight(22)}{rightPad}";
/// var engineering3Figures = $"{leftPad}{a.ToEngineeringNotation(3)}";
/// Console.WriteLine($"/// {original}{engineering}{engineering3Figures}");
/// }
/// Console.ReadLine();
/// }
///
/// private static IEnumerable<double> SampleNumbers
/// {
/// get
/// {
/// var testValues = new[]
/// {
/// Double.NaN,
/// Double.Epsilon,
/// Double.MinValue,
/// Double.MaxValue,
/// Double.NegativeInfinity,
/// Double.PositiveInfinity,
/// -300,
/// -30,
/// -1.1,
/// -1,
/// -0.1,
/// -0.01,
/// -0.001,
/// -0.0001,
/// 0,
/// 0.0001,
/// 0.001,
/// 0.01,
/// 0.1,
/// 1,
/// 1.1,
/// 30,
/// 300
/// };
///
/// foreach (double a in testValues)
/// {
/// yield return a;
/// }
/// for (int i = 28; i >= -28; --i)
/// {
/// yield return Math.Pow(10, i) * -9.995567890123;
/// yield return Math.Pow(10, i) * -1.234567890123;
/// yield return Math.Pow(10, i) * -1.235567890123;
/// }
/// for (int i = -28; i <= 28; ++i)
/// {
/// yield return Math.Pow(10, i) * 9.995567890123;
/// yield return Math.Pow(10, i) * 1.234567890123;
/// yield return Math.Pow(10, i) * 1.235567890123;
/// }
/// }
/// }
/// }
/// Gives the following output
///
/// NaN -> NaN -> NaN
/// 5E-324 -> 5E-324 -> 5E-324
/// -1.7976931348623157E+308--> -179.76931348623157E+306--> -180E+306
/// 1.7976931348623157E+308-> 179.76931348623157E+306-> 180E+306
/// -8 --> -8 --> -8
/// 8 -> 8 -> 8
/// -300 --> -300 --> -300
/// -30 --> -30 --> -30
/// -1.1 --> -1.1 --> -1.1
/// -1 --> -1 --> -1
/// -0.1 --> -100m --> -100m
/// -0.01 --> -10m --> -10m
/// -0.001 --> -1m --> -1m
/// -0.0001 --> -100µ --> -100µ
/// 0 -> 0 -> 0
/// 0.0001 -> 100µ -> 100µ
/// 0.001 -> 1m -> 1m
/// 0.01 -> 10m -> 10m
/// 0.1 -> 100m -> 100m
/// 1 -> 1 -> 1
/// 1.1 -> 1.1 -> 1.1
/// 30 -> 30 -> 30
/// 300 -> 300 -> 300
/// -9.995567890123E+28 --> -99.95567890123E+27 --> -100E+27
/// -1.2345678901229999E+28--> -12.345678901229999E+27--> -12.3E+27
/// -1.235567890123E+28 --> -12.35567890123E+27 --> -12.4E+27
/// -9.995567890123E+27 --> -9.995567890123E+27 --> -10.0E+27
/// -1.234567890123E+27 --> -1.234567890123E+27 --> -1.23E+27
/// -1.2355678901230001E+27--> -1.2355678901230001E+27--> -1.24E+27
/// -9.995567890123001E+26--> -999.5567890123001Y --> -1.00E+27
/// -1.234567890123E+26 --> -123.4567890123Y --> -123Y
/// -1.2355678901230002E+26--> -123.55678901230002Y --> -124Y
/// -9.995567890123001E+25--> -99.95567890123001Y --> -100Y
/// -1.234567890123E+25 --> -12.34567890123Y --> -12.3Y
/// -1.2355678901230002E+25--> -12.355678901230002Y --> -12.4Y
/// -9.995567890123001E+24--> -9.995567890123001Y --> -10.0Y
/// -1.234567890123E+24 --> -1.234567890123Y --> -1.23Y
/// -1.235567890123E+24 --> -1.235567890123Y --> -1.24Y
/// -9.995567890123001E+23--> -999.5567890123001Z --> -1.00Y
/// -1.234567890123E+23 --> -123.4567890123Z --> -123Z
/// -1.2355678901230002E+23--> -123.55678901230002Z --> -124Z
/// -9.995567890123E+22 --> -99.95567890123Z --> -100Z
/// -1.234567890123E+22 --> -12.34567890123Z --> -12.3Z
/// -1.235567890123E+22 --> -12.35567890123Z --> -12.4Z
/// -9.995567890123001E+21--> -9.995567890123001Z --> -10.0Z
/// -1.2345678901229999E+21--> -1.2345678901229999Z --> -1.23Z
/// -1.235567890123E+21 --> -1.235567890123Z --> -1.24Z
/// -9.995567890123E+20 --> -999.5567890123E --> -1.00Z
/// -1.2345678901229999E+20--> -123.45678901229999E --> -123E
/// -1.235567890123E+20 --> -123.5567890123E --> -124E
/// -9.995567890123001E+19--> -99.95567890123001E --> -100E
/// -1.234567890123E+19 --> -12.34567890123E --> -12.3E
/// -1.235567890123E+19 --> -12.35567890123E --> -12.4E
/// -9.995567890123E+18 --> -9.995567890123E --> -10.0E
/// -1.234567890123E+18 --> -1.234567890123E --> -1.23E
/// -1.235567890123E+18 --> -1.235567890123E --> -1.24E
/// -9.995567890123E+17 --> -999.5567890123P --> -1.00E
/// -1.234567890123E+17 --> -123.4567890123P --> -123P
/// -1.235567890123E+17 --> -123.5567890123P --> -124P
/// -99955678901230000 --> -99.95567890123P --> -100P
/// -12345678901230000 --> -12.34567890123P --> -12.3P
/// -12355678901230000 --> -12.35567890123P --> -12.4P
/// -9995567890123000 --> -9.995567890123P --> -10.0P
/// -1234567890123000 --> -1.234567890123P --> -1.23P
/// -1235567890123000 --> -1.235567890123P --> -1.24P
/// -999556789012300 --> -999.5567890123T --> -1.00P
/// -123456789012300 --> -123.4567890123T --> -123T
/// -123556789012300 --> -123.5567890123T --> -124T
/// -99955678901230 --> -99.95567890123T --> -100T
/// -12345678901230 --> -12.34567890123T --> -12.3T
/// -12355678901230 --> -12.35567890123T --> -12.4T
/// -9995567890123 --> -9.995567890123T --> -10.0T
/// -1234567890123 --> -1.234567890123T --> -1.23T
/// -1235567890123 --> -1.235567890123T --> -1.24T
/// -999556789012.3 --> -999.5567890123G --> -1.00T
/// -123456789012.29999 --> -123.45678901229999G --> -123G
/// -123556789012.3 --> -123.5567890123G --> -124G
/// -99955678901.23001 --> -99.95567890123001G --> -100G
/// -12345678901.23 --> -12.34567890123G --> -12.3G
/// -12355678901.230001 --> -12.355678901230001G --> -12.4G
/// -9995567890.123001 --> -9.995567890123001G --> -10.0G
/// -1234567890.123 --> -1.234567890123G --> -1.23G
/// -1235567890.1230001 --> -1.2355678901230001G --> -1.24G
/// -999556789.0123 --> -999.5567890123M --> -1.00G
/// -123456789.0123 --> -123.4567890123M --> -123M
/// -123556789.0123 --> -123.5567890123M --> -124M
/// -99955678.90123 --> -99.95567890123M --> -100M
/// -12345678.90123 --> -12.34567890123M --> -12.3M
/// -12355678.90123 --> -12.35567890123M --> -12.4M
/// -9995567.890123 --> -9.995567890123M --> -10.0M
/// -1234567.890123 --> -1.234567890123M --> -1.23M
/// -1235567.8901230001 --> -1.2355678901230001M --> -1.24M
/// -999556.7890123001 --> -999.5567890123001k --> -1.00M
/// -123456.7890123 --> -123.4567890123k --> -123k
/// -123556.78901230001 --> -123.55678901230001k --> -124k
/// -99955.67890123 --> -99.95567890123k --> -100k
/// -12345.67890123 --> -12.34567890123k --> -12.3k
/// -12355.678901230001 --> -12.355678901230001k --> -12.4k
/// -9995.567890123 --> -9.995567890123k --> -10.0k
/// -1234.5678901229999 --> -1.2345678901229999k --> -1.23k
/// -1235.567890123 --> -1.235567890123k --> -1.24k
/// -999.5567890123001 --> -999.5567890123001 --> -1.00k
/// -123.45678901229999 --> -123.45678901229999 --> -123
/// -123.5567890123 --> -123.5567890123 --> -124
/// -99.95567890123 --> -99.95567890123 --> -100
/// -12.345678901229999 --> -12.345678901229999 --> -12.3
/// -12.35567890123 --> -12.35567890123 --> -12.4
/// -9.995567890123 --> -9.995567890123 --> -10.0
/// -1.234567890123 --> -1.234567890123 --> -1.23
/// -1.235567890123 --> -1.235567890123 --> -1.24
/// -0.9995567890123 --> -999.5567890123m --> -1.00
/// -0.1234567890123 --> -123.4567890123m --> -123m
/// -0.12355678901230001 --> -123.55678901230001m --> -124m
/// -0.09995567890123001 --> -99.95567890123001m --> -100m
/// -0.01234567890123 --> -12.34567890123m --> -12.3m
/// -0.01235567890123 --> -12.35567890123m --> -12.4m
/// -0.009995567890123 --> -9.995567890123m --> -10.0m
/// -0.001234567890123 --> -1.234567890123m --> -1.23m
/// -0.0012355678901230002--> -1.2355678901230002m --> -1.24m
/// -0.0009995567890123001--> -999.5567890123001µ --> -1.00m
/// -0.0001234567890123 --> -123.4567890123µ --> -123µ
/// -0.0001235567890123 --> -123.5567890123µ --> -124µ
/// -9.995567890123001E-05--> -99.95567890123001µ --> -100µ
/// -1.234567890123E-05 --> -12.34567890123µ --> -12.3µ
/// -1.2355678901230002E-05--> -12.355678901230002µ --> -12.4µ
/// -9.995567890123E-06 --> -9.995567890123µ --> -10.0µ
/// -1.234567890123E-06 --> -1.234567890123µ --> -1.23µ
/// -1.235567890123E-06 --> -1.235567890123µ --> -1.24µ
/// -9.995567890123E-07 --> -999.5567890123n --> -1.00µ
/// -1.234567890123E-07 --> -123.4567890123n --> -123n
/// -1.235567890123E-07 --> -123.5567890123n --> -124n
/// -9.995567890123E-08 --> -99.95567890123n --> -100n
/// -1.234567890123E-08 --> -12.34567890123n --> -12.3n
/// -1.2355678901230001E-08--> -12.355678901230001n --> -12.4n
/// -9.995567890123E-09 --> -9.995567890123n --> -10.0n
/// -1.234567890123E-09 --> -1.234567890123n --> -1.23n
/// -1.2355678901230001E-09--> -1.2355678901230001n --> -1.24n
/// -9.995567890123E-10 --> -999.5567890123p --> -1.00n
/// -1.234567890123E-10 --> -123.4567890123p --> -123p
/// -1.235567890123E-10 --> -123.5567890123p --> -124p
/// -9.995567890123E-11 --> -99.95567890123p --> -100p
/// -1.2345678901229998E-11--> -12.345678901229998p --> -12.3p
/// -1.235567890123E-11 --> -12.35567890123p --> -12.4p
/// -9.995567890123E-12 --> -9.995567890123p --> -10.0p
/// -1.2345678901229999E-12--> -1.2345678901229999p --> -1.23p
/// -1.235567890123E-12 --> -1.235567890123p --> -1.24p
/// -9.995567890123E-13 --> -999.5567890123f --> -1.00p
/// -1.234567890123E-13 --> -123.4567890123f --> -123f
/// -1.2355678901230002E-13--> -123.55678901230002f --> -124f
/// -9.995567890123001E-14--> -99.95567890123001f --> -100f
/// -1.2345678901229999E-14--> -12.345678901229999f --> -12.3f
/// -1.235567890123E-14 --> -12.35567890123f --> -12.4f
/// -9.995567890123002E-15--> -9.995567890123002f --> -10.0f
/// -1.234567890123E-15 --> -1.234567890123f --> -1.23f
/// -1.2355678901230002E-15--> -1.2355678901230002f --> -1.24f
/// -9.995567890123E-16 --> -999.5567890123a --> -1.00f
/// -1.234567890123E-16 --> -123.4567890123a --> -123a
/// -1.2355678901230001E-16--> -123.55678901230001a --> -124a
/// -9.995567890123001E-17--> -99.95567890123001a --> -100a
/// -1.234567890123E-17 --> -12.34567890123a --> -12.3a
/// -1.2355678901230001E-17--> -12.355678901230001a --> -12.4a
/// -9.995567890123002E-18--> -9.995567890123002a --> -10.0a
/// -1.234567890123E-18 --> -1.234567890123a --> -1.23a
/// -1.2355678901230002E-18--> -1.2355678901230002a --> -1.24a
/// -9.995567890123E-19 --> -999.5567890123z --> -1.00a
/// -1.2345678901229999E-19--> -123.45678901229999z --> -123z
/// -1.235567890123E-19 --> -123.5567890123z --> -124z
/// -9.995567890123E-20 --> -99.95567890123z --> -100z
/// -1.2345678901229999E-20--> -12.345678901229999z --> -12.3z
/// -1.235567890123E-20 --> -12.35567890123z --> -12.4z
/// -9.995567890122999E-21--> -9.995567890122999z --> -10.0z
/// -1.2345678901229998E-21--> -1.2345678901229998z --> -1.23z
/// -1.2355678901229999E-21--> -1.2355678901229999z --> -1.24z
/// -9.995567890123002E-22--> -999.5567890123002y --> -1.00z
/// -1.234567890123E-22 --> -123.4567890123y --> -123y
/// -1.235567890123E-22 --> -123.5567890123y --> -124y
/// -9.995567890123E-23 --> -99.95567890123y --> -100y
/// -1.2345678901229999E-23--> -12.345678901229999y --> -12.3y
/// -1.235567890123E-23 --> -12.35567890123y --> -12.4y
/// -9.995567890123E-24 --> -9.995567890123y --> -10.0y
/// -1.234567890123E-24 --> -1.234567890123y --> -1.23y
/// -1.235567890123E-24 --> -1.235567890123y --> -1.24y
/// -9.995567890123E-25 --> -999.5567890123E-27 --> -1.00y
/// -1.234567890123E-25 --> -123.4567890123E-27 --> -123E-27
/// -1.2355678901230002E-25--> -123.55678901230002E-27--> -124E-27
/// -9.995567890123E-26 --> -99.95567890123E-27 --> -100E-27
/// -1.234567890123E-26 --> -12.34567890123E-27 --> -12.3E-27
/// -1.2355678901230001E-26--> -12.355678901230001E-27--> -12.4E-27
/// -9.995567890123001E-27--> -9.995567890123001E-27--> -10.0E-27
/// -1.2345678901229999E-27--> -1.2345678901229999E-27--> -1.23E-27
/// -1.2355678901230001E-27--> -1.2355678901230001E-27--> -1.24E-27
/// -9.995567890123E-28 --> -999.5567890123E-30 --> -1.00E-27
/// -1.2345678901229998E-28--> -123.45678901229998E-30--> -123E-30
/// -1.235567890123E-28 --> -123.5567890123E-30 --> -124E-30
/// 9.995567890123E-28 -> 999.5567890123E-30 -> 1.00E-27
/// 1.2345678901229998E-28-> 123.45678901229998E-30-> 123E-30
/// 1.235567890123E-28 -> 123.5567890123E-30 -> 124E-30
/// 9.995567890123001E-27 -> 9.995567890123001E-27 -> 10.0E-27
/// 1.2345678901229999E-27-> 1.2345678901229999E-27-> 1.23E-27
/// 1.2355678901230001E-27-> 1.2355678901230001E-27-> 1.24E-27
/// 9.995567890123E-26 -> 99.95567890123E-27 -> 100E-27
/// 1.234567890123E-26 -> 12.34567890123E-27 -> 12.3E-27
/// 1.2355678901230001E-26-> 12.355678901230001E-27-> 12.4E-27
/// 9.995567890123E-25 -> 999.5567890123E-27 -> 1.00y
/// 1.234567890123E-25 -> 123.4567890123E-27 -> 123E-27
/// 1.2355678901230002E-25-> 123.55678901230002E-27-> 124E-27
/// 9.995567890123E-24 -> 9.995567890123y -> 10.0y
/// 1.234567890123E-24 -> 1.234567890123y -> 1.23y
/// 1.235567890123E-24 -> 1.235567890123y -> 1.24y
/// 9.995567890123E-23 -> 99.95567890123y -> 100y
/// 1.2345678901229999E-23-> 12.345678901229999y -> 12.3y
/// 1.235567890123E-23 -> 12.35567890123y -> 12.4y
/// 9.995567890123002E-22 -> 999.5567890123002y -> 1.00z
/// 1.234567890123E-22 -> 123.4567890123y -> 123y
/// 1.235567890123E-22 -> 123.5567890123y -> 124y
/// 9.995567890122999E-21 -> 9.995567890122999z -> 10.0z
/// 1.2345678901229998E-21-> 1.2345678901229998z -> 1.23z
/// 1.2355678901229999E-21-> 1.2355678901229999z -> 1.24z
/// 9.995567890123E-20 -> 99.95567890123z -> 100z
/// 1.2345678901229999E-20-> 12.345678901229999z -> 12.3z
/// 1.235567890123E-20 -> 12.35567890123z -> 12.4z
/// 9.995567890123E-19 -> 999.5567890123z -> 1.00a
/// 1.2345678901229999E-19-> 123.45678901229999z -> 123z
/// 1.235567890123E-19 -> 123.5567890123z -> 124z
/// 9.995567890123002E-18 -> 9.995567890123002a -> 10.0a
/// 1.234567890123E-18 -> 1.234567890123a -> 1.23a
/// 1.2355678901230002E-18-> 1.2355678901230002a -> 1.24a
/// 9.995567890123001E-17 -> 99.95567890123001a -> 100a
/// 1.234567890123E-17 -> 12.34567890123a -> 12.3a
/// 1.2355678901230001E-17-> 12.355678901230001a -> 12.4a
/// 9.995567890123E-16 -> 999.5567890123a -> 1.00f
/// 1.234567890123E-16 -> 123.4567890123a -> 123a
/// 1.2355678901230001E-16-> 123.55678901230001a -> 124a
/// 9.995567890123002E-15 -> 9.995567890123002f -> 10.0f
/// 1.234567890123E-15 -> 1.234567890123f -> 1.23f
/// 1.2355678901230002E-15-> 1.2355678901230002f -> 1.24f
/// 9.995567890123001E-14 -> 99.95567890123001f -> 100f
/// 1.2345678901229999E-14-> 12.345678901229999f -> 12.3f
/// 1.235567890123E-14 -> 12.35567890123f -> 12.4f
/// 9.995567890123E-13 -> 999.5567890123f -> 1.00p
/// 1.234567890123E-13 -> 123.4567890123f -> 123f
/// 1.2355678901230002E-13-> 123.55678901230002f -> 124f
/// 9.995567890123E-12 -> 9.995567890123p -> 10.0p
/// 1.2345678901229999E-12-> 1.2345678901229999p -> 1.23p
/// 1.235567890123E-12 -> 1.235567890123p -> 1.24p
/// 9.995567890123E-11 -> 99.95567890123p -> 100p
/// 1.2345678901229998E-11-> 12.345678901229998p -> 12.3p
/// 1.235567890123E-11 -> 12.35567890123p -> 12.4p
/// 9.995567890123E-10 -> 999.5567890123p -> 1.00n
/// 1.234567890123E-10 -> 123.4567890123p -> 123p
/// 1.235567890123E-10 -> 123.5567890123p -> 124p
/// 9.995567890123E-09 -> 9.995567890123n -> 10.0n
/// 1.234567890123E-09 -> 1.234567890123n -> 1.23n
/// 1.2355678901230001E-09-> 1.2355678901230001n -> 1.24n
/// 9.995567890123E-08 -> 99.95567890123n -> 100n
/// 1.234567890123E-08 -> 12.34567890123n -> 12.3n
/// 1.2355678901230001E-08-> 12.355678901230001n -> 12.4n
/// 9.995567890123E-07 -> 999.5567890123n -> 1.00µ
/// 1.234567890123E-07 -> 123.4567890123n -> 123n
/// 1.235567890123E-07 -> 123.5567890123n -> 124n
/// 9.995567890123E-06 -> 9.995567890123µ -> 10.0µ
/// 1.234567890123E-06 -> 1.234567890123µ -> 1.23µ
/// 1.235567890123E-06 -> 1.235567890123µ -> 1.24µ
/// 9.995567890123001E-05 -> 99.95567890123001µ -> 100µ
/// 1.234567890123E-05 -> 12.34567890123µ -> 12.3µ
/// 1.2355678901230002E-05-> 12.355678901230002µ -> 12.4µ
/// 0.0009995567890123001 -> 999.5567890123001µ -> 1.00m
/// 0.0001234567890123 -> 123.4567890123µ -> 123µ
/// 0.0001235567890123 -> 123.5567890123µ -> 124µ
/// 0.009995567890123 -> 9.995567890123m -> 10.0m
/// 0.001234567890123 -> 1.234567890123m -> 1.23m
/// 0.0012355678901230002 -> 1.2355678901230002m -> 1.24m
/// 0.09995567890123001 -> 99.95567890123001m -> 100m
/// 0.01234567890123 -> 12.34567890123m -> 12.3m
/// 0.01235567890123 -> 12.35567890123m -> 12.4m
/// 0.9995567890123 -> 999.5567890123m -> 1.00
/// 0.1234567890123 -> 123.4567890123m -> 123m
/// 0.12355678901230001 -> 123.55678901230001m -> 124m
/// 9.995567890123 -> 9.995567890123 -> 10.0
/// 1.234567890123 -> 1.234567890123 -> 1.23
/// 1.235567890123 -> 1.235567890123 -> 1.24
/// 99.95567890123 -> 99.95567890123 -> 100
/// 12.345678901229999 -> 12.345678901229999 -> 12.3
/// 12.35567890123 -> 12.35567890123 -> 12.4
/// 999.5567890123001 -> 999.5567890123001 -> 1.00k
/// 123.45678901229999 -> 123.45678901229999 -> 123
/// 123.5567890123 -> 123.5567890123 -> 124
/// 9995.567890123 -> 9.995567890123k -> 10.0k
/// 1234.5678901229999 -> 1.2345678901229999k -> 1.23k
/// 1235.567890123 -> 1.235567890123k -> 1.24k
/// 99955.67890123 -> 99.95567890123k -> 100k
/// 12345.67890123 -> 12.34567890123k -> 12.3k
/// 12355.678901230001 -> 12.355678901230001k -> 12.4k
/// 999556.7890123001 -> 999.5567890123001k -> 1.00M
/// 123456.7890123 -> 123.4567890123k -> 123k
/// 123556.78901230001 -> 123.55678901230001k -> 124k
/// 9995567.890123 -> 9.995567890123M -> 10.0M
/// 1234567.890123 -> 1.234567890123M -> 1.23M
/// 1235567.8901230001 -> 1.2355678901230001M -> 1.24M
/// 99955678.90123 -> 99.95567890123M -> 100M
/// 12345678.90123 -> 12.34567890123M -> 12.3M
/// 12355678.90123 -> 12.35567890123M -> 12.4M
/// 999556789.0123 -> 999.5567890123M -> 1.00G
/// 123456789.0123 -> 123.4567890123M -> 123M
/// 123556789.0123 -> 123.5567890123M -> 124M
/// 9995567890.123001 -> 9.995567890123001G -> 10.0G
/// 1234567890.123 -> 1.234567890123G -> 1.23G
/// 1235567890.1230001 -> 1.2355678901230001G -> 1.24G
/// 99955678901.23001 -> 99.95567890123001G -> 100G
/// 12345678901.23 -> 12.34567890123G -> 12.3G
/// 12355678901.230001 -> 12.355678901230001G -> 12.4G
/// 999556789012.3 -> 999.5567890123G -> 1.00T
/// 123456789012.29999 -> 123.45678901229999G -> 123G
/// 123556789012.3 -> 123.5567890123G -> 124G
/// 9995567890123 -> 9.995567890123T -> 10.0T
/// 1234567890123 -> 1.234567890123T -> 1.23T
/// 1235567890123 -> 1.235567890123T -> 1.24T
/// 99955678901230 -> 99.95567890123T -> 100T
/// 12345678901230 -> 12.34567890123T -> 12.3T
/// 12355678901230 -> 12.35567890123T -> 12.4T
/// 999556789012300 -> 999.5567890123T -> 1.00P
/// 123456789012300 -> 123.4567890123T -> 123T
/// 123556789012300 -> 123.5567890123T -> 124T
/// 9995567890123000 -> 9.995567890123P -> 10.0P
/// 1234567890123000 -> 1.234567890123P -> 1.23P
/// 1235567890123000 -> 1.235567890123P -> 1.24P
/// 99955678901230000 -> 99.95567890123P -> 100P
/// 12345678901230000 -> 12.34567890123P -> 12.3P
/// 12355678901230000 -> 12.35567890123P -> 12.4P
/// 9.995567890123E+17 -> 999.5567890123P -> 1.00E
/// 1.234567890123E+17 -> 123.4567890123P -> 123P
/// 1.235567890123E+17 -> 123.5567890123P -> 124P
/// 9.995567890123E+18 -> 9.995567890123E -> 10.0E
/// 1.234567890123E+18 -> 1.234567890123E -> 1.23E
/// 1.235567890123E+18 -> 1.235567890123E -> 1.24E
/// 9.995567890123001E+19 -> 99.95567890123001E -> 100E
/// 1.234567890123E+19 -> 12.34567890123E
This is an old thread, but the answer might as well be correct. Issues with the existing code: it doesn't handle NaN, any of the infinities, negative numbers, or very small number (like double.Epsilon). And you can't pass in a precision.
My code is:
static string DoubleToEngineering(double value, string displayPrecision)
{
string Retval;
if (double.IsNaN(value)
|| double.IsInfinity(value)
|| double.IsNegativeInfinity(value)
|| double.IsPositiveInfinity(value)
|| value == 0.0
)
{
Retval = String.Format("{0:" + "F" + displayPrecision + "}", value);
return Retval;
}
bool isNeg = value < 0;
if (isNeg) value = -value;
int exp = (int)(Math.Floor(Math.Log10(value) / 3.0) * 3.0);
int powerToRaise = -exp;
double newValue = value;
// Problem: epsilon is something-324
// The biggest possible number is somethinge306
// You simply can't do a Math.Power (10, 324), it becomes infiniity.
if (powerToRaise > 300)
{
powerToRaise -= 300;
newValue = newValue * Math.Pow(10.0, 300);
}
newValue = newValue * Math.Pow(10.0, powerToRaise);
// I don't know when this below is triggered.
if (newValue >= 1000.0)
{
newValue = newValue / 1000.0;
exp = exp + 3;
}
var fmt = "{0:F" + displayPrecision + "}";
Retval = String.Format (fmt, newValue);
if (exp != 0) Retval += String.Format("e{0}", exp);
if (isNeg) Retval = "-" + Retval;
return Retval;
}
Test cases are below. My personal standard for test cases (sorry, this doesn't follow the latest and best NUnit guidance): the public static Test() takes no parameters and return the number of errors. It normally calls a private static TestOne(args, expected) which calculates the actual value, compared to the expected value, and returns the number of errors.
private static int TestDoubleToEngineeringOne(double value, string expected)
{
var fakePrecision = "4";
int NError = 0;
var actual = DoubleToEngineering(value, fakePrecision);
if (actual != expected)
{
System.Diagnostics.Debug.WriteLine($"ERROR: DoubleToEngineering({value}) expected {expected} actual {actual}");
NError++;
}
return NError;
}
public static int TestDoubleToEngineering()
{
int NError = 0;
NError += TestDoubleToEngineeringOne(0, "0.0000");
NError += TestDoubleToEngineeringOne(1, "1.0000");
NError += TestDoubleToEngineeringOne(2, "2.0000");
NError += TestDoubleToEngineeringOne(3, "3.0000");
NError += TestDoubleToEngineeringOne(10, "10.0000");
NError += TestDoubleToEngineeringOne(999, "999.0000");
NError += TestDoubleToEngineeringOne(1000, "1.0000e3");
NError += TestDoubleToEngineeringOne(1.234E21, "1.2340e21");
NError += TestDoubleToEngineeringOne(-1, "-1.0000");
NError += TestDoubleToEngineeringOne(-999, "-999.0000");
NError += TestDoubleToEngineeringOne(-1000, "-1.0000e3");
NError += TestDoubleToEngineeringOne(0.1, "100.0000e-3");
NError += TestDoubleToEngineeringOne(0.02, "20.0000e-3");
NError += TestDoubleToEngineeringOne(0.003, "3.0000e-3");
NError += TestDoubleToEngineeringOne(0.0004, "400.0000e-6");
NError += TestDoubleToEngineeringOne(0.00005, "50.0000e-6");
NError += TestDoubleToEngineeringOne(double.NaN, "NaN");
NError += TestDoubleToEngineeringOne(double.PositiveInfinity, "∞");
NError += TestDoubleToEngineeringOne(double.NegativeInfinity, "-∞");
NError += TestDoubleToEngineeringOne(double.Epsilon, "4.9407e-324");
NError += TestDoubleToEngineeringOne(double.MaxValue, "179.7693e306");
NError += TestDoubleToEngineeringOne(double.MinValue, "-179.7693e306");
return NError;
}
ICustomFormmatter using a private dictionary for the symbols.
class EngNotationFormatter : IFormatProvider, ICustomFormatter
{
private readonly Dictionary<double, string> notationSymbols = new Dictionary<double, string>
{
{double.NegativeInfinity, ""}, //Handles when value is 0
{-24, "y"},
{-21, "z"},
{-18, "a"},
{-15, "f"},
{-12, "p"},
{-9, "n"},
{-6, "μ"},
{-3, "m"},
{0, ""},
{3, "k"},
{6, "M"},
{9, "G"},
{12, "T"},
{15, "P"},
{18, "E"},
{21, "Z"},
{24, "Y"},
};
public string Format(string format, object arg, IFormatProvider formatProvider)
{
double value = Convert.ToDouble(arg);
double exponent = Math.Log10(Math.Abs(value));
double engExponent = Math.Floor(exponent / 3) * 3;
string symbol = notationSymbols.ContainsKey(engExponent) ? notationSymbols[engExponent] : "e" + engExponent;
return (value * Math.Pow(10, (int)-engExponent)) + symbol;
}
public object GetFormat(Type formatType)
{
if (formatType == typeof(ICustomFormatter))
return this;
else
return null;
}
}
Example use
(0.00005678).ToString(new EngNotationFormatter()); //56.78μ
(0.1234).ToString(new EngNotationFormatter()); //123.4m
(0).ToString(new EngNotationFormatter()); //0
(1300).ToString(new EngNotationFormatter()); //1.3k
(19000).ToString(new EngNotationFormatter()); //19k
Here is a method:
public static string GetNumberWithUnitPrefix(double number, int power = 1)
{
char[] incPrefixes = new[] { 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' };
char[] decPrefixes = new[] { 'm', 'µ', 'n', 'p', 'f', 'a', 'z', 'y' };
int degree = (int)Math.Floor(Math.Log10(Math.Abs(number)) / (3 * (double)power));
double scaled = number * Math.Pow(1000, -(degree * power));
char? prefix = null;
switch (Math.Sign(degree))
{
case 1: prefix = incPrefixes[degree - 1]; break;
case -1: prefix = decPrefixes[-degree - 1]; break;
}
return ToStringWithSeparator(MathFunctions.RoundToSignificantDigits(scaled, 4)).ToString() + prefix;
}
use the power input (in this case 2) if you want to convert m² to mm² for example
(improved answer form Formatting a number with a metric prefix?)
To solve this problem, you want to create a class (call it Engineering) which inherits from Float on which you override the ToString() member.
Edit: Okay, I understand the issue now. Still, the solution is subclassing.