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
Use my Format
method as follows:
Engineering.Format(1.5e-4, 3, true); // Returns "150µ"
Table of example values below after the code.
public static class Engineering
{
static Engineering()
{
System.Globalization.CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentCulture;
DecimalSeparator = ci.NumberFormat.NumberDecimalSeparator;
}
static readonly string DecimalSeparator;
const string ExponentFormat = "'E'+0;'E'-0;''"; // Format sections pos;neg;zero
const string SIPrefixesSmall = "mµnpfa";
const string SIPrefixesLarge = "kMGTPE";
/// <summary>
/// Format a double using engineering notation (the exponent will be a multiple of 3.)
/// </summary>
public static string Format(double value, int digits, bool useSIprefixes)
{
if (double.IsNaN(value) ||
double.IsInfinity(value))
{
return value.ToString();
}
if (digits < 1)
{
throw new ArgumentException("The digits parameter must be greater than zero.");
}
if (value == 0d)
{
return 0d.ToString($"F{digits - 1}") + FormatExponent(useSIprefixes, 0);
}
string sign = "";
if (value < 0d)
{
sign = "-";
value = -value;
}
// Custom exponential formatting using '#' will give us exactly our digits plus an exponent
string scientific = value.ToString(new string('#', digits) + "E0");
string significand = scientific.Remove(digits);
int exponent = int.Parse(scientific.Substring(digits + 1));
// (significand now already contains the requested number of digits with no decimal separator in it)
// Round the exponent to a multiple of three in the negative direction (towards -inf)
int r = exponent < 0 ? -2 : 0;
int exponent2 = (exponent + r) / 3 * 3;
int digits2 = digits + exponent - exponent2;
// Decide on the number of digits before the decimal
int before = digits2 % 3;
if (before == 0) before = 3;
exponent2 += digits2 - before;
// Decimal placement and final formatting
string s = significand;
if (before > digits) s += new string('0', before - digits);
if (before < digits2) s = s.Insert(before, DecimalSeparator);
return sign + s + FormatExponent(useSIprefixes, exponent2);
}
static string FormatExponent(bool useSIPrefixes, int e)
{
if (useSIPrefixes)
{
int i = Math.Abs(e) / 3 - 1;
if (e > 0 && i < SIPrefixesLarge.Length) return SIPrefixesLarge[i].ToString();
if (e < 0 && i < SIPrefixesSmall.Length) return SIPrefixesSmall[i].ToString();
}
return e.ToString(ExponentFormat);
}
}
Table of example values:
value digits: 1 (exp.) 1 2 3 4 6
=============================================================================================================
0 0 0 0.0 0.00 0.000 0.00000
1 1 1 1.0 1.00 1.000 1.00000
10 10 10 10 10.0 10.00 10.0000
100 100 100 100 100 100.0 100.000
1000 1E+3 1k 1.0k 1.00k 1.000k 1.00000k
10000 10E+3 10k 10k 10.0k 10.00k 10.0000k
100000 100E+3 100k 100k 100k 100.0k 100.000k
1000000 1E+6 1M 1.0M 1.00M 1.000M 1.00000M
10000000 10E+6 10M 10M 10.0M 10.00M 10.0000M
100000000 100E+6 100M 100M 100M 100.0M 100.000M
1000000000 1E+9 1G 1.0G 1.00G 1.000G 1.00000G
0.1 100E-3 100m 100m 100m 100.0m 100.000m
0.01 10E-3 10m 10m 10.0m 10.00m 10.0000m
0.001 1E-3 1m 1.0m 1.00m 1.000m 1.00000m
0.0001 100E-6 100µ 100µ 100µ 100.0µ 100.000µ
1E-05 10E-6 10µ 10µ 10.0µ 10.00µ 10.0000µ
1E-06 1E-6 1µ 1.0µ 1.00µ 1.000µ 1.00000µ
1E-07 100E-9 100n 100n 100n 100.0n 100.000n
1E-08 10E-9 10n 10n 10.0n 10.00n 10.0000n
1E-09 1E-9 1n 1.0n 1.00n 1.000n 1.00000n
1E-10 100E-12 100p 100p 100p 100.0p 100.000p
0.086 90E-3 90m 86m 86.0m 86.00m 86.0000m
0.00030908 300E-6 300µ 310µ 309µ 309.1µ 309.080µ
1239451 1E+6 1M 1.2M 1.24M 1.239M 1.23945M
5084611353 5E+9 5G 5.1G 5.08G 5.085G 5.08461G
8.46113537656557E-18 8E-18 8a 8.5a 8.46a 8.461a 8.46114a
50.8437 50 50 51 50.8 50.84 50.8437
50.846 50 50 51 50.8 50.85 50.8460
990 1E+3 1k 990 990 990.0 990.000
1500 2E+3 2k 1.5k 1.50k 1.500k 1.50000k
1490 1E+3 1k 1.5k 1.49k 1.490k 1.49000k
-990 -1E+3 -1k -990 -990 -990.0 -990.000
-1500 -2E+3 -2k -1.5k -1.50k -1.500k -1.50000k
-1490 -1E+3 -1k -1.5k -1.49k -1.490k -1.49000k
-5488 -5E+3 -5k -5.5k -5.49k -5.488k -5.48800k
7.89E-05 80E-6 80µ 79µ 78.9µ 78.90µ 78.9000µ
50.84611353765656 50 50 51 50.8 50.85 50.8461
0.073699979 70E-3 70m 74m 73.7m 73.70m 73.7000m
0.8 800E-3 800m 800m 800m 800.0m 800.000m
0.999 1 1 1.0 999m 999.0m 999.000m
0.111 100E-3 100m 110m 111m 111.0m 111.000m
0.111111 100E-3 100m 110m 111m 111.1m 111.111m
NaN NaN NaN NaN NaN NaN NaN
∞ ∞ ∞ ∞ ∞ ∞ ∞
-∞ -∞ -∞ -∞ -∞ -∞ -∞
=============================================================================================================
1 (exp.) 1 2 3 4 6
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.
© 2022 - 2024 — McMap. All rights reserved.