2016-04-04 5 views
0

Ich habe eine Variable, die eine Menge in einer gegebenen Einheit darstellt:Int64 als Ergebnis von doppelten Zeiten 10^x?

enum Unit 
{ 
    Single, 
    Thousand, 
    Million, 
    Billion, 
    Trillion 
} 

public class Quantity() 
{ 

    public double number; 
    public Unit numberUnit; 

    public Int64 GetNumberInSingleUnits() 
    { 
    // ??? 
    } 

} 

Zum Beispiel vorstellen,

var GDP_Of_America = new Quantiy { number = 16.66, numberUnit = Unit.Trillion }; 
Int64 gdp = GDP_Of_America.GetNumberinSingleUnits(); // should return 16,660,000,000,000 

Meine Frage ist im Grunde - wie kann ich die "GetNumberInSingleUnits" Funktion implementieren? Ich kann nicht einfach mit einigen UInt64-Faktor, z.

 double num = 0.5; 
     UInt64 factor = 1000000000000; 

     var result = num * factor; // won't work! results in double 

Da die regelmäßigen numerischen Operationen Reslt in einem doppelten, aber das Ergebnis kann als der Bereich gültiger Doppel größer sein.

Wie könnte ich diese Konvertierung machen?

ps, ​​Ich weiß, die Klasse "Quantity" ist keine gute Möglichkeit, Informationen zu speichern - aber das ist gebunden an die Eingabedaten meiner Anwendung, die in nicht-einzelnen (z. B. Millionen, Milliarden usw.) Einheiten ist.

+0

Sind Sie sicher, dass ein 'Int64' eine höhere Zahl als ein' double' enthalten kann? – Rawling

+0

Jetzt bin ich völlig verwirrt. Es scheint richtig, dass Double.MinValue <= Int64.MinValue und Double.MaxValue> = Int64.MaxValue. Wie ist das überhaupt möglich? Beide sind 8-Byte-Typen. – Bogey

+0

Zu spät für die Bearbeitung, aber: In Ordnung, es scheint, als wäre es eine Frage der Genauigkeit, mit Double nur 100% genau bis 2^54 - was bedeutet, dass Int64 höchstwahrscheinlich immer noch die bessere Option für mich wäre – Bogey

Antwort

2

Wie ich schon sagte, decimal s kann Ihnen dabei helfen:

public enum Unit 
{ 
    Micro = -6, Milli = -3, Centi = -2, Deci = -1, 
    One /* Don't really like this name */, Deca, Hecto, Kilo, Mega = 6, Giga = 9 
} 

public struct Quantity 
{ 
    public decimal Value { get; private set; } 

    public Unit Unit { get; private set; } 

    public Quantity(decimal value, Unit unit) : 
     this() 
    { 
     Value = value; 
     Unit = unit; 
    } 

    public decimal OneValue /* This one either */ 
    { 
     get 
     { 
      return Value * (decimal)Math.Pow(10, (int)Unit); 
     } 
    } 
} 

Mit decimal s Sie werden nicht viel Präzision bis verlieren, nachdem Sie entscheiden, sie zu long konvertieren (und passen sie von Über-/Unterschreitungen).

+0

Danke Anton, super Input. Ich muss sehen, ob ich auf diese Weise mit Ungenauigkeiten konfrontiert werde, aber die ersten Tests sehen ziemlich gut aus. Ich habe an einen zweiten Weg gedacht, werde unten posten - wird aber deine als Antwort markieren, da es viel sauberer aussieht. – Bogey

+0

Die 'Math.Pow (10, (int) Unit)' spielt nicht gut mit den 'Mega' und' Giga', da ihre Lücke größer als 10 mal ist. – grek40

+0

@ grek40 Whoops, mein Schlechter. Ich weiß nicht, was ich dachte. Fest. –

0

Antons Antwort scheint eine gute Lösung zu sein. Nur um der Diskussion willen, ein anderer möglicher Weg.

Ich mag dieses überhaupt nicht, weil es sehr unordentlich scheint; Jedoch denke ich, dass Ungenauigkeiten vermeiden könnte, wenn diese jemals ein Problem mit Dezimalzahlen sein sollten.

public Int64 GetAsInt64(double number) 
{ 
    // Returns 1 for single units, 3 for thousands, 6 for millions, etc. 
    uint e = GetFactorExponent(); 

    // Converts to scientific notation 
    // e.g. number = -1.2345, unit millions to "-1.2345e6" 
    string str = String.Format("{0:#,0.###########################}", number) + "e" + e; 

    // Parses scientific notation into Int64 
    Int64 result = Int64.Parse(str, NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent | NumberStyles.AllowThousands); 
    return result; 
}