Gibt es eine Möglichkeit, die "signifikanten Zahlen" einer Dezimalstelle zu ermitteln?
OK, nach einigen Nachforschungen und zum großen Teil dank der hilfreichen Antworten von Jon und Hans, konnte ich dies zusammenstellen. Bisher scheint es gut zu funktionieren. Ich würde mein Leben natürlich nicht auf die absolute Korrektheit wetten.
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 einige Beispiele für Ein- / Ausgänge:
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).
Mit diesem Code stelle ich mir vor, ich würde mein Ziel erreichen, indem ich Folgendes mache:
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 das aber noch nicht wirklich durchgearbeitet. Wer sich austauschen möchte: das wäre sehr dankbar!
Original QuestionAngenommen, ich habe diesen Code geschrieben:
decimal a = 1.23M;
decimal b = 1.23000M;
Console.WriteLine(a);
Console.WriteLine(b);
Der obige Befehl gibt Folgendes aus:
1.23 1.23000
Ich finde, dass das auch funktioniert, wenn ich @ benutdecimal.Parse("1.23")
zuma
unddecimal.Parse("1.23000")
zumb
(Dies bedeutet, dass diese Frage für Fälle gilt, in denen das Programm Benutzereingaben empfängt.)
So klar eindecimal
value ist sich irgendwie "bewusst", wie ich es nennPräzisio. Ich sehe jedoch keine Mitglieder auf demdecimal
-Typ, der neben @ eine beliebige Zugriffsmöglichkeit bietToString
selbst.
Angenommen, ich wollte zwei multiplizierendecimal
Werte und trimmen Sie das Ergebnis auf die Genauigkeit des weniger genauen Arguments. Mit anderen Worten
decimal a = 123.4M;
decimal b = 5.6789M;
decimal x = a / b;
Console.WriteLine(x);
Die obigen Ausgaben:
21.729560302171195125816619416
Was ich frage ist: Wie könnte ich eine Methode schreiben, die @ zurückgeben wür21.73
statt (seit123.4M
hat vier signifikante Zahlen)?
Um klar zu sein: Mir ist klar, dass ich @ anrufen könntToString
ählen Sie bei beiden Argumenten die signifikanten Ziffern in jeder Zeichenfolge und runden Sie das Ergebnis der Berechnung mit dieser Zahl. Ich suche eineander Weise, wenn möglich.
(ICHebenfall Beachten Sie, dass Sie in den meisten Szenarien, in denen Sie mit wichtigen Zahlen zu tun haben, wahrscheinlich nicht das @ verwenden müssedecimal
Art. Aber ich frage, weil, wie ich am Anfang erwähnte, diedecimal
Arterschein, um Informationen zur Genauigkeit einzuschließen, währenddouble
nicht, soweit ich weiß.)