Gibt es eine Möglichkeit, die „signifikante Zahlen“ eine Dezimalzahl zu bekommen?
-
02-10-2019 - |
Frage
Update
OK, nach einigen Untersuchungen, und Dank im großen Teil auf die hilfreichen Antworten von Jon zur Verfügung gestellt und Hans, das ist, was ich in der Lage war, zusammen zu stellen. Bisher ich denke, es scheint gut zu funktionieren. Ich würde wetten, mein Leben nicht auf seiner Gesamt Richtigkeit, natürlich.
public static int GetSignificantDigitCount(this decimal value)
{
/* So, the decimal type is basically represented as a fraction of two
* integers: a numerator that can be anything, and a denominator that is
* some power of 10.
*
* For example, the following numbers are represented by
* the corresponding fractions:
*
* VALUE NUMERATOR DENOMINATOR
* 1 1 1
* 1.0 10 10
* 1.012 1012 1000
* 0.04 4 100
* 12.01 1201 100
*
* So basically, if the magnitude is greater than or equal to one,
* the number of digits is the number of digits in the numerator.
* If it's less than one, the number of digits is the number of digits
* in the denominator.
*/
int[] bits = decimal.GetBits(value);
if (value >= 1M || value <= -1M)
{
int highPart = bits[2];
int middlePart = bits[1];
int lowPart = bits[0];
decimal num = new decimal(lowPart, middlePart, highPart, false, 0);
int exponent = (int)Math.Ceiling(Math.Log10((double)num));
return exponent;
}
else
{
int scalePart = bits[3];
// Accoring to MSDN, the exponent is represented by
// bits 16-23 (the 2nd word):
// http://msdn.microsoft.com/en-us/library/system.decimal.getbits.aspx
int exponent = (scalePart & 0x00FF0000) >> 16;
return exponent + 1;
}
}
Ich habe es nicht so gründlich getestet. Hier sind ein paar Beispiel-Ein- / Ausgänge, aber:
Value Precision 0 1 digit(s). 0.000 4 digit(s). 1.23 3 digit(s). 12.324 5 digit(s). 1.2300 5 digit(s). -5 1 digit(s). -5.01 3 digit(s). -0.012 4 digit(s). -0.100 4 digit(s). 0.0 2 digit(s). 10443.31 7 digit(s). -130.340 6 digit(s). -80.8000 6 digit(s).
Sie diesen Code verwenden, ich denke, ich würde mein Ziel erreichen durch so etwas wie dies zu tun:
public static decimal DivideUsingLesserPrecision(decimal x, decimal y)
{
int xDigitCount = x.GetSignificantDigitCount();
int yDigitCount = y.GetSignificantDigitCount();
int lesserPrecision = System.Math.Min(xDigitCount, yDigitCount);
return System.Math.Round(x / y, lesserPrecision);
}
Ich habe nicht wirklich fertig, durch diese Arbeit, though. Jeder, der auf Aktien Gedanken will: so viel geschätzt würde
Original Question
Angenommen, ich habe diesen Code schreiben:
decimal a = 1.23M;
decimal b = 1.23000M;
Console.WriteLine(a);
Console.WriteLine(b);
Die oben gezeigten Wille Ausgabe:
1.23 1.23000
Ich finde, dass dies funktioniert auch, wenn ich decimal.Parse("1.23")
für a
und decimal.Parse("1.23000")
für b
verwenden (was bedeutet, diese Frage auf Fälle anwendbar ist, wenn das Programm eine Benutzereingabe empfängt).
So eindeutig ein decimal
Wert ist irgendwie „bewusst“, was ich werde seine Genauigkeit . Ich sehe jedoch keine Mitglieder auf der decimal
Typ, der jede mögliche Weise den Zugriff auf diese bieten, abgesehen von ToString
selbst.
Angenommen, ich wollte zwei decimal
Werte multiplizieren und das Ergebnis an die Präzision des ungenauen Arguments trimmen. Mit anderen Worten:
decimal a = 123.4M;
decimal b = 5.6789M;
decimal x = a / b;
Console.WriteLine(x);
Die obigen Ausgänge:
21.729560302171195125816619416
Was ich frage ist: Wie kann ich eine Methode schreiben, die 21.73
statt zurückkehren würde (da 123.4M
vier signifikante Ziffern hat)
Um klar zu sein: Ich weiß, ich ToString
auf beiden Argumenten nennen könnte, die signifikanten Zahlen in jeder Kette zählen und diese Zahl verwenden, um das Ergebnis der Berechnung runden. Ich suche ein andere Art und Weise, wenn möglich.
(I auch erkennt, dass in den meisten Szenarien, in denen man es zu tun mit signifikanten Zahlen, brauchen Sie vermutlich nicht den decimal
Typen verwendet werden. Aber ich frage, weil, wie ich bereits erwähnt am Anfang, der decimal
Typ erscheint enthält Informationen über Präzision, während double
nicht, soweit ich weiß.)
Lösung
Sie können mit Decimal.GetBits
die bekommen Rohdaten und Arbeit es aus, dass.
Leider habe ich keine Zeit zu schreiben Beispielcode zur Zeit - und Sie wollen wahrscheinlich zu verwenden
Andere Tipps
Ja, im Gegensatz zu Punkttypen schwimmen, System.Decimal hält im wörtlichen der Anzahl der Stellen verfolgen. Dies ist ein Merkmal von Decimal.Parse (), ob Sie sich von Ihrem Code ausgeführt oder durch den Compiler, wenn er eine wörtliche in Ihrem Programm analysiert. Sie können diese Informationen wiederherstellen, in den Code in meiner Antwort überprüfen dieses Thema .
Wiederherstellen der Anzahl der signifikanten Stellen, nachdem Sie Mathe auf dem Wert zu tun, scheint mir eine lange gedreht. Keine Ahnung, ob die Betreiber sie bewahren, lassen Sie es uns wissen, was Sie herausfinden.
Die Lösung oben fällt aus dem Bett schnell mit Werten wie 1200, in dem die Anzahl der signifikanten Ziffern 2, aber die Funktion zurückkehrt 4. Vielleicht gibt eine konsistente Art und Weise ist mit einer solchen Situation zu umgehen dh zu überprüfen, um sicher Rückgabewert machen nicht funktioniert umfassen Nullen in dem ganzzahligen Anteil ohne einen Bruchteil nachlauf.