4

Suppose I have two numbers, 0.0001 and 0.00001.

When I try to format them using "e" notation in C#, I get the following:

double val = 0.0001;
Console.Out.WriteLine(val.ToString("e")) //prints 1e-4

double val2 = 0.00001;
Console.Out.WriteLine(val2.ToString("e")) //prints 1e-5

But I would like to format both 0.0001 and 0.00001 to show the same exponent like this:

0.0001-> 100e-6 0.00001->10e-6

How can I achieve this?

sbenderli
  • 3,654
  • 9
  • 35
  • 48
  • 2
    You would have to write a method to do this. Scientific notation specifies that the number before the "e" be between 1 (inclusive) and 10 (exclusive), or zero. Stated another way, there must be exactly one digit to the left of the decimal point, and, if that digit is zero, all the digits to the right of the decimal point must also be zero. – phoog Apr 13 '12 at 17:05
  • See also this question: http://stackoverflow.com/questions/808104/engineering-notation-in-c – Ethan Brown Apr 13 '12 at 17:06

2 Answers2

6

If you want this result:

    1.0      = 1.00
    0.1      = 0.10
    0.01     = 0.010
    0.001    = 1.00e-3
    0.0001   = 0.10e-3
    0.00001  = 0.010e-3
    0.000001 = 1.00e-6

The use this code:

class Program
{
    /// <summary>
    /// Format a value using engineering notation.
    /// </summary>
    /// <example>
    ///     Format("S4",-12345678.9) = "-12.34e-6"
    ///     with 4 significant digits
    /// </example>
    /// <arg name="format">The format specifier</arg>
    /// <arg name="value">The value</arg>
    /// <returns>A string representing the value formatted according to the format specifier</returns>
    public static string Format(string format, double value)
    {
        if(format.StartsWith("S"))
        {
            string dg=format.Substring(1);
            int significant_digits;
            int.TryParse(dg, out significant_digits);
            if(significant_digits==0) significant_digits=4;
            int sign;
            double amt;
            int exponent;
            SplitEngineeringParts(value, out sign, out amt, out exponent);
            return ComposeEngrFormat(significant_digits, sign, amt, exponent);
        }
        else
        {
            return value.ToString(format);
        }
    }
    static void SplitEngineeringParts(double value,
                out int sign,
                out double new_value,
                out int exponent)
    {
        sign=Math.Sign(value);
        value=Math.Abs(value);
        if(value>0.0)
        {
            if(value>1.0)
            {
                exponent=(int)(Math.Floor(Math.Log10(value)/3.0)*3.0);
            }
            else
            {
                exponent=(int)(Math.Ceiling(Math.Log10(value)/3.0)*3.0);
            }
        }
        else
        {
            exponent=0;
        }
        new_value=value*Math.Pow(10.0, -exponent);
        if(new_value>=1e3)
        {
            new_value/=1e3;
            exponent+=3;
        }
        if(new_value<=1e-3&&new_value>0)
        {
            new_value*=1e3;
            exponent-=3;
        }
    }
    static string ComposeEngrFormat(int significant_digits, int sign, double v, int exponent)
    {
        int expsign=Math.Sign(exponent);
        exponent=Math.Abs(exponent);
        int digits=v>0?(int)Math.Log10(v)+1:0;
        int decimals=Math.Max(significant_digits-digits, 0);
        double round=Math.Pow(10, -decimals);
        digits=v>0?(int)Math.Log10(v+0.5*round)+1:0;
        decimals=Math.Max(significant_digits-digits, 0);
        string t;
        string f="0:F";
        if(exponent==0)
        {
            t=string.Format("{"+f+decimals+"}", sign*v);
        }
        else
        {
            t=string.Format("{"+f+decimals+"}e{1}", sign*v, expsign*exponent);
        }
        return t;
    }

    static void Main(string[] args)
    {
        Console.WriteLine("\t1.0      = {0}", Format("S3", 1.0));
        Console.WriteLine("\t0.1      = {0}", Format("S3", 0.1));
        Console.WriteLine("\t0.01     = {0}", Format("S3", 0.01));
        Console.WriteLine("\t0.001    = {0}", Format("S3", 0.001));
        Console.WriteLine("\t0.0001   = {0}", Format("S3", 0.0001));
        Console.WriteLine("\t0.00001  = {0}", Format("S3", 0.00001));
        Console.WriteLine("\t0.000001 = {0}", Format("S3", 0.000001));
    }
}
John Alexiou
  • 28,472
  • 11
  • 77
  • 133
0

I wanted to add a simpler way of doing the same thing as my other answer

/// <summary>
/// Format a number with scientific exponents and specified sigificant digits.
/// </summary>
/// <param name="x">The value to format</param>
/// <param name="significant_digits">The number of siginicant digits to show</param>
/// <returns>The fomratted string</returns>
public static string Sci(this double x, int significant_digits)
{
    //Check for special numbers and non-numbers
    if (double.IsInfinity(x)||double.IsNaN(x)||x==0)
    {
        return x.ToString();
    }
    // extract sign so we deal with positive numbers only
    int sign=Math.Sign(x);
    x=Math.Abs(x);
    // get scientific exponent, 10^3, 10^6, ...
    int sci=(int)Math.Floor(Math.Log(x, 10)/3)*3;
    // scale number to exponent found
    x=x*Math.Pow(10, -sci);
    // find number of digits to the left of the decimal
    int dg=(int)Math.Floor(Math.Log(x, 10))+1;
    // adjust decimals to display
    int decimals=Math.Min(significant_digits-dg, 15);
    // format for the decimals
    string fmt=new string('0', decimals);
    if (sci==0)
    {
        //no exponent
        return string.Format("{0}{1:0."+fmt+"}",
            sign<0?"-":string.Empty,
            Math.Round(x, decimals));
    }
    int index=sci/3+6;
    // with 10^exp format
    return string.Format("{0}{1:0."+fmt+"}e{2}",
        sign<0?"-":string.Empty,
        Math.Round(x, decimals),
        sci);
}

So the test code

double x = 10000*Math.PI;
for (int i = 0; i < 12; i++)
{
    Debug.Print("{0,-25} {1,-12}", x, x.Sci(3));
    x/=10;
 }

produces the following output:

x                         x.Sci(3)
31415.9265358979          31.4e3      
3141.59265358979          3.14e3      
314.159265358979          314         
31.4159265358979          31.4        
3.14159265358979          3.14        
0.314159265358979         314e-3      
0.0314159265358979        31.4e-3     
0.00314159265358979       3.14e-3     
0.000314159265358979      314e-6      
3.14159265358979E-05      31.4e-6     
3.14159265358979E-06      3.14e-6     
3.14159265358979E-07      314e-9      
John Alexiou
  • 28,472
  • 11
  • 77
  • 133