2012-04-12 18 views
9

Estoy portando el programa de C# a java. Me he enfrentado a un hecho queMath "pow" en Java y C# devuelven resultados ligeramente diferentes?

Java

Math.pow(0.392156862745098,1./3.) = 0.7319587495200227 

C#

Math.Pow(0.392156862745098, 1.0/3.0) =0.73195874952002271 

este último dígito conduce a diferencias suficientes en los cálculos posteriores. ¿Hay alguna forma de emular el pow de C#?

Gracias

+5

Su código ni siquiera dar resultados reproducibles en .NET, así olvidarse de él . Relacionado: http://stackoverflow.com/questions/6683059/are-floating-point-numbers-consistent-in-c-can-they-be – CodesInChaos

+12

¿De verdad? ¿El décimo séptimo dígito significante le está dando "suficientes diferencias en otros cálculos"? ¿Puede darnos un ejemplo? –

+2

Si lo compara con calc.exe y wolfram alpha, el 1 es incorrecto de todos modos. Me quedaría con la implementación de Java. –

Respuesta

34

Sólo para confirmar lo que escribió Chris Shain, consigo los mismos valores binarios:

// Java 
public class Test 
{ 
    public static void main(String[] args) 
    { 
     double input = 0.392156862745098; 
     double pow = Math.pow(input, 1.0/3.0);    
     System.out.println(Double.doubleToLongBits(pow)); 
    } 
} 

// C# 
using System; 

public class Test 
{ 
    static void Main() 
    { 
     double input = 0.392156862745098; 
     double pow = Math.Pow(input, 1.0/3.0);    
     Console.WriteLine(BitConverter.DoubleToInt64Bits(pow)); 
    } 
} 

salida de ambos: 4604768117848454313

En otras palabras, los valores dobles son exactamente el mismo patrón de bits , y cualquier diferencia que esté viendo (suponiendo que obtenga los mismos resultados) se debe al formato en lugar de una diferencia en el valor. Por cierto, el valor exacto de ese doble es

0.73195874952002271118800535987247712910175323486328125 

Ahora vale la pena señalar que las cosas claramente extrañas pueden suceder en aritmética de punto, sobre todo cuando optimizaciones permiten la aritmética de 80 bits en algunas situaciones pero no en otras, etc. flotando

Como dice Henk, si una diferencia en el último bit o two le causa problemas, entonces su diseño está roto.

+2

+1 para el seguimiento que muestra la equivalencia de salida binaria. –

+1

* "pueden ocurrir cosas muy extrañas en la aritmética de coma flotante, particularmente cuando las optimizaciones permiten la aritmética de 80 bits" * - Para más información, vea mi [pregunta sobre la consistencia de punto flotante C#] (http://stackoverflow.com/questions/ 6683059/are-floating-point-numbers-consistent-in-c-can-they-be) –

+0

No, Math.pow es diferente en C# y java. Considere Double.doubleToLongBits (Math.pow (0.39215686274509803,1.0/3.0)) y BitConverter.DoubleToInt64Bits (Math.Pow (0.39215686274509803,1.0/3.0)). –

18

Si sus cálculos son sensibles a este tipo de diferencia, entonces necesitará otras medidas (un rediseño).

+6

No puedo estar en desacuerdo, pero esta no es una gran "respuesta" en sí misma ... –

+3

No es una respuesta directa, no. Pero ese es el problema con [XY problems] (http://meta.stackexchange.com/questions/66377). ¿Esperas que una parte del código de Java "emule el pow de C#"? –

8

Tanto Java como C# devuelven un número de coma flotante IEEE (específicamente, un doble) de Math.Pow. La diferencia que está viendo se debe casi con certeza al formateo cuando visualiza el número como decimal. El valor subyacente (binario) es probablemente el mismo, y sus problemas matemáticos se encuentran en otra parte.

+1

Es muy posible que los últimos dígitos difieran realmente. .net no garantiza resultados específicos, y hace uso de esa libertad. – CodesInChaos

+1

Ambos devuelven un valor double * typed *; sin embargo, a menos que haya un FPU "POW" que se use (por ejemplo, es una función de la FPU, no hay configuraciones "estrictas" en los idiomas), el algoritmo utilizado podría ser sutilmente diferente ... sería interesante tener un pequeño fragmento para mostrar esto de cualquier manera aquí, sin embargo. –

1

La aritmética de coma flotante es inherentemente imprecisa. Usted afirma que la respuesta de C# es "mejor", pero ninguna de ellas es tan precisa. Por ejemplo, Wolfram Alpha (que es mucho más preciso de hecho) da a estos valores:

http://www.wolframalpha.com/input/?i=Pow%280.392156862745098%2C+1.0+%2F+3.0%29

Si la diferencia de una unidad en el dígito 17a está causando cálculos posteriores a ir mal, entonces yo creo que hay un problema con su matemática, no con la implementación de Java de pow. Debe pensar en cómo reestructurar sus cálculos para que no dependan de esas diferencias menores.

+0

Hay situaciones en las que no le importan los últimos dígitos de los resultados reales, siempre que sean consistentes y reproducibles. Pero en ese caso no puede usar los tipos de puntos flotantes integrados de .net. – CodesInChaos

+1

He sido corregido en este punto: la matemática en coma flotante es muy precisa.El problema es que opera con números ** binarios **, por lo que puede no haber una conversión precisa, de terminación de decimal a binaria (de manera similar, no hay una representación de terminación precisa de 1/3 en decimal, pero en base-3 sería expresarse como .1). Si sus entradas no se pueden expresar con precisión en binario, se redondearán, y si formatea su salida como decimal, puede redondearse de nuevo. –

+0

"Muy preciso" es un término subjetivo. Es probable que sea más preciso de lo que necesitarás a menos que trabajes con sistemas altamente caóticos. Mi punto es que, con un número limitado de espacio de almacenamiento (64 bits), existe un límite superior a la precisión con la que se pueden expresar los números, independientemente de la base. –

13

este último dígito conduce a diferencias suficientes en los cálculos posteriores

Eso es imposible, porque son el mismo número.Un double no tiene suficiente precisión para distinguir entre 0.7319587495200227 y 0.73195874952002271; los dos están representados como

0.73195874952002271118800535987247712910175323486328125. 

La diferencia es el redondeo: Java está utilizando 16 dígitos significativos y C# está utilizando 17. Pero eso es sólo una cuestión pantalla. precisión

Cuestiones relacionadas