Actualización
Bien, después de algunas investigaciones, y gracias en gran parte a las útiles respuestas proporcionadas por Jon y Hans, esto es lo que pude juntar. Hasta ahora, creo que parece funcionar bien. No apostaría mi vida por su total corrección, por supuesto.¿Hay alguna forma de obtener las "cifras significativas" de un decimal?
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;
}
}
No lo he probado a fondo. Aquí hay algunas entradas/salidas de la muestra, sin embargo:
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).
Usando este código, imagino yo lograr mi objetivo de hacer algo como esto:
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);
}
realmente no he terminado de trabajar a través esto, sin embargo. Cualquiera que quiera compartir pensamientos: ¡sería muy apreciado!
pregunta original
Supongamos que tengo escribir este código:
decimal a = 1.23M;
decimal b = 1.23000M;
Console.WriteLine(a);
Console.WriteLine(b);
Lo anterior es la salida:
1.23 1.23000
Me parece que esto también funciona si uso decimal.Parse("1.23")
de a
y decimal.Parse("1.23000")
para b
(whi ch significa que esta pregunta se aplica a los casos en que el programa recibe la entrada del usuario).
Así que claramente un valor de decimal
es de alguna manera "consciente" de lo que llamaré su precisión. Sin embargo, no veo miembros en el tipo decimal
que proporcionen ninguna forma de acceder a esto, aparte del ToString
.
Supongamos que quiero multiplicar dos valores de decimal
y recortar el resultado con la precisión del argumento menos preciso. En otras palabras:
decimal a = 123.4M;
decimal b = 5.6789M;
decimal x = a/b;
Console.WriteLine(x);
Las salidas anteriores:
21.729560302171195125816619416
Lo que estoy preguntando es: ¿cómo podría escribir un método que devolvería 21.73
lugar (ya que 123.4M
tiene cuatro cifras significativas)?
Para ser claros: me doy cuenta de que podría llamar a ToString
en ambos argumentos, contar las cifras significativas en cada cadena, y usar este número para redondear el resultado del cálculo. Estoy buscando manera diferente, si es posible.
(tambiéndan cuenta de que en la mayoría de escenarios en los que está tratando con cifras significativas, es probable que no necesita utilizar el tipo decimal
. Pero Lo digo porque, como he mencionado al principio, el decimal
tipo aparece para incluir información acerca de la precisión, mientras que double
no, hasta donde yo sé.)
¡No sabía que quería saber esto hasta que me lo pidiera +1! – msarchet
Su función no funciona correctamente para algunas de esas entradas. Por ejemplo, -0.012 tiene solo 2 dígitos significativos, no 4. –
@JamesJones Claramente se está refiriendo a un concepto diferente de dígitos significativos, no que uno aprendería en un curso de matemáticas. Tal vez el nombre "dígitos usados" tendría más sentido. – ErikE