tags:

views:

588

answers:

5

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.

A: 

There's nothing built in.

However this forum thread has some code examples:

http://www.techtalkz.com/c-c-sharp/191675-does-c-have-built-way-format-numbers-like.html

Kevin Laity
A: 

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.

McWafflestix
No, it's engineering notation.
Joey Robert
I don't think the reference is to distance necessarily. It just happened that he used an example with "m" which could be, say, milliseconds (ms), millimeters (mm), milliamps (mA), etc.
Scott W
The question is not about distances, it's about engineering notation for numbers; 1 mili = 0.001, 1 micro = 0.000001, 1 kilo = 1000, etc.
Kevin Laity
Gotcha; I think I was most confused by the "mu" symbol, which I have learned to read as "micron". :-)
McWafflestix
Structs cannot be subclassed. A good approach is to do what highlycaffeinated said: Implement a formatter.Implement an extension method that returns a formatted string is also a good one.
Rafael Romão
+3  A: 

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() );
tvanfosson
+3  A: 

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";
    }
}
Patrick McDonald
Isn't `kilo` with a small `k` ? (Ref: http://en.wikipedia.org/wiki/SI_prefix)
jalexiou
Indeed it is, updated answer
Patrick McDonald
If you want to be *really* pedantic, there should also be a space between the number and the unit (Ref: http://en.wikipedia.org/wiki/International_System_of_Units#SI_writing_style).
Al
+5  A: 

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()));
highlycaffeinated