2010-11-08 22 views

Respuesta

5

En la mayoría de los casos que impliquen un decimal (moneda, etc.), no es útil para tomar una raíz; y la raíz no tendrá nada como la precisión esperada que podría esperar tener un decimal. Por supuesto, puede forzarlo por colada (suponiendo que no se trata de extremos de la gama decimal):

decimal root = (decimal)Math.Sqrt((double)myVariableHere); 

que obliga a reconocer por lo menos los problemas inherentes de redondeo.

+3

Bueno, estoy haciendo una aplicación calcula la proporción áurea, que eventualmente irá al rango decimal. No funcionará en mi escenario. – Ave

-3

Simple: envíe su decimal a y llame a la función, obtenga el resultado y vuélvala a un decimal. Probablemente sea más rápido que cualquiera de las funciones de sqrt que pueda hacer por su cuenta y ahorrará mucho esfuerzo.

-3
Math.Sqrt((double)myVariableHere); 

le va a devolver un doble que es la raíz cuadrada de su decimalmyVariableHere.

44

No entiendo por qué todas las respuestas a esa pregunta son las mismas.

Hay varias formas de calcular la raíz cuadrada a partir de un número. Uno de ellos fue propuesto por Isaac Newton. Solo escribiré una de las implementaciones más simples de este método. Lo uso para mejorar la precisión de la raíz cuadrada doble.

// x - a number, from which we need to calculate the square root 
// epsilon - an accuracy of calculation of the root from our number. 
// The result of the calculations will differ from an actual value 
// of the root on less than epslion. 
public static decimal Sqrt(decimal x, decimal epsilon = 0.0M) 
{ 
    if (x < 0) throw new OverflowException("Cannot calculate square root from a negative number"); 

    decimal current = (decimal)Math.Sqrt((double)x), previous; 
    do 
    { 
     previous = current; 
     if (previous == 0.0M) return 0; 
     current = (previous + x/previous)/2; 
    } 
    while (Math.Abs(previous - current) > epsilon); 
    return current; 
} 

Acerca de la velocidad: en el peor caso (epsilon = 0 y el número es decimal.MaxValue) el bucle se repite a menos de tres veces.

Si usted quiere saber más, lea this (Hacker's Delight by Henry S. Warren, Jr.)

2

me encontré con esta pregunta, y me gustaría sugerir un algoritmo diferente a la que SLenik propuso. Esto se basa en el Babylonian Method.

public static decimal Sqrt(decimal x, decimal? guess = null) 
{ 
    var ourGuess = guess.GetValueOrDefault(x/2m); 
    var result = x/ourGuess; 
    var average = (ourGuess + result)/2m; 

    if (average == ourGuess) // This checks for the maximum precision possible with a decimal. 
     return average; 
    else 
     return Sqrt(x, average); 
} 

No requiere el uso de la función existente Sqrt, y por lo tanto evita la conversión a double y la espalda, con la consiguiente pérdida de precisión.

+0

Bobson, usted propuso otra posible solución, pero no hay ningún defecto en la solución de SLenik porque solo usa el doble Sqrt (doble) como punto de partida, como una semilla. Luego, en el ciclo, usa el decimal de precisión completo 'x' para ajustar el valor resultante de Sqrt. – farfareast

+0

@farfareast: es un punto válido y, en la mayoría de los casos, el problema de precisión no tendrá importancia. pero si tiene un decimal muy preciso en primer lugar, perderá una parte del mismo, lo que podría provocar un resultado levemente desagradable. También me resulta filosóficamente objetable calcular la raíz cuadrada usando la raíz cuadrada, aunque eso ciertamente no me impediría codificar eso si realmente lo necesitaba y había una razón de rendimiento para hacerlo. – Bobson

+0

Además, en mi prueba inicial (y posterior), mi algoritmo parecía ser algo así como 100 veces más rápido, pero luego de otras pruebas, descubrí que el orden en que hice las pruebas afectó los resultados, así que eliminé esa parte. Sigue siendo un algoritmo válido, y creo que es un poco más rápido, pero es solo una diferencia menor. La versión 'doble 'incorporada de' Sqrt' es todavía significativamente más rápida que cualquiera de las dos. – Bobson

Cuestiones relacionadas