Aggiornamento
OK, dopo alcune indagini, e grazie in gran parte alle utili risposte fornite da Jon e Hans, questo è quello che sono stato in grado di mettere insieme. Finora penso che sembra funzionare bene. Non scommetterei la mia vita sulla sua totale correttezza, ovviamente.C'è un modo per ottenere le "cifre significative" di un decimale?
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;
}
}
Non l'ho provato a fondo. Qui ci sono un paio di ingressi/uscite del campione, però:
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).
Utilizzando questo codice, immagino vorrei realizzare il mio obiettivo facendo qualcosa di simile a questo:
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);
}
non ho davvero finito di lavorare attraverso questo, però. Chiunque voglia condividere pensieri: sarebbe molto apprezzato!
domanda iniziale
Supponiamo che io ho scrivere questo codice:
decimal a = 1.23M;
decimal b = 1.23000M;
Console.WriteLine(a);
Console.WriteLine(b);
l'uscita sarà sopra:
1.23 1.23000
Trovo che questo funziona anche se uso decimal.Parse("1.23")
per a
e decimal.Parse("1.23000")
per b
(whi ch significa che questa domanda si applica ai casi in cui il programma riceve input dell'utente).
Quindi chiaramente un valore di decimal
è in qualche modo "consapevole" di ciò che chiamerò la sua precisione . Tuttavia, non vedo membri sul tipo decimal
che forniscono un modo per accedere a questo, a parte lo stesso ToString
.
Supponiamo di voler moltiplicare due valori decimal
e di tagliare il risultato alla precisione dell'argomento meno preciso. In altre parole:
decimal a = 123.4M;
decimal b = 5.6789M;
decimal x = a/b;
Console.WriteLine(x);
Le uscite di cui sopra:
21.729560302171195125816619416
Quello che mi chiedo è: come potrei scrivere un metodo che sarebbe tornato 21.73
invece (dal 123.4M
ha quattro cifre significative)?
Per essere chiari: mi rendo conto che potrei chiamare ToString
su entrambi gli argomenti, contare le cifre significative in ogni stringa e utilizzare questo numero per arrotondare il risultato del calcolo. Sto cercando uno diverso modo, se possibile.
(I anche si rendono conto che nella maggior parte degli scenari in cui hai a che fare con le figure significative, probabilmente non c'è bisogno di utilizzare il tipo di decimal
. Ma mi chiedo perché, come ho detto all'inizio, il decimal
appare per includere informazioni sulla precisione, mentre double
non lo fa, per quanto ne so.)
Non sapevo che volevo sapere questo finché non lo hai chiesto +1! – msarchet
La tua funzione non funziona correttamente per alcuni di questi ingressi. Ad esempio, -0.012 è solo 2 cifre significative - non 4. –
@JamesJones Chiaramente si riferisce a un diverso concetto di cifre significative, non che si apprenderebbe in un corso di matematica. Forse il nome "cifre usate" avrebbe più senso. – ErikE