Lo que todo programador debería saber sobre aritmética de punto flotante
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Traducidos capítulos sobre comparación y propagación de errores

+84 -63
+63 -38
errors/comparison/index.html
··· 2 2 <html lang="es"> 3 3 <head> 4 4 <meta charset="utf-8"> 5 - <title>La Guía del Punto Flotante - Comparison</title> 5 + <title>La Guía del Punto Flotante - Comparación</title> 6 6 7 7 <meta name="generator" content="nanoc 3.1.2"> 8 8 9 - <meta name="Description" content="Explanation of the various pitfalls in comparing floating-point numbers."> 9 + <meta name="Description" content="Explicación de los diversos problemas al comparar números de punto flotante"> 10 10 11 11 <link rel="stylesheet" type="text/css" href="/style.css" media="screen"> 12 12 <link rel="shortcut icon" href="/favicon.ico" type="image/vnd.microsoft.icon"> ··· 14 14 </head> 15 15 <body> 16 16 <div id="main"> 17 - <h1>Comparison</h1> 18 - <p>Due to rounding errors, most <a href="/formats/fp/">floating-point</a> numbers end up being slightly imprecise. As long as this 19 - imprecision stays small, it can usually be ignored. However, it also means that numbers expected 20 - to be equal (e.g. when calculating the same result through different correct methods) often differ 21 - slightly, and a simple equality test fails. For example:</p> 17 + <h1>Comparación</h1> 18 + <p>Debido a los errores de redondeo, la mayoría de los números de <a href="/formats/fp/">punto flotante</a> 19 + terminan siendo ligeramente imprecisos. Mientras esta imprecisión se mantenga pequeña, 20 + normalmente se puede ignorar. Sin embargo, esto significa también que números que se 21 + espera que sean iguales (por ejemplo al calcular el mismo resultado utilizando distintos 22 + métodos correctos) a veces difieren levemente, y una simple prueba de igualdad falla. 23 + Por ejemplo:</p> 22 24 23 25 <pre><code> float a = 0.15 + 0.15 24 26 float b = 0.1 + 0.2 25 - if(a == b) // can be false! 26 - if(a &gt;= b) // can also be false! 27 + if(a == b) // ¡Puede ser falso! 28 + if(a &gt;= b) // ¡También puede ser falso! 27 29 </code></pre> 28 30 29 - <h2 id="dont-use-absolute-error-margins">Don’t use absolute error margins</h2> 30 - <p>The solution is to check not whether the numbers are exactly the same, but whether their difference is 31 - very small. The error margin that the difference is compared to is often called <em>epsilon</em>. 32 - The most simple form:</p> 31 + <h2 id="no-usar-mrgenes-de-error-absolutos">No usar márgenes de error absolutos</h2> 32 + 33 + <p>La solución es comprobar no si los números son exactamente iguales, sino si su 34 + diferencia es muy pequeña. El margen de error frente al que se compara esta diferencia 35 + normalmente se llama <em>epsilon</em>. En su forma más simple:</p> 33 36 34 - <pre><code> if( Math.abs(a-b) &lt; 0.00001) // wrong - don't do this 37 + <pre><code> if(Math.abs(a-b) &lt; 0.00001) // Mal - no hacer esto 35 38 </code></pre> 36 39 37 - <p>This is a bad way to do it because a fixed epsilon chosen because it “looks small” could actually be way too 38 - large when the numbers being compared are very small as well. The comparison would return “true” for numbers that are quite different. And when the numbers are very large, the epsilon 39 - could end up being smaller than the smallest rounding error, so that the comparison always returns “false”. 40 - Therefore, it is necessary to see whether the <em>relative error</em> is smaller than epsilon:</p> 40 + <p>Esto es una mala forma de hacerlo porque un epsilon fijo elegido porque «parece 41 + pequeño» podría perfectamente ser demasiado grande cuando los números que se 42 + comparan son también muy pequeños. La comparación devolvería «verdadero» para 43 + números muy diferentes. Y cuando los números son muy grandes, el epsilon 44 + puede acabar siendo más pequeño que el mínimo error de redondeo, por lo que 45 + la comparación siempre devolvería «falso». Por tanto, es necesario ver si 46 + el <em>error relativo</em> es menor epsilon:</p> 41 47 42 - <pre><code> if( Math.abs((a-b)/b) &lt; 0.00001 ) // still not right! 48 + <pre><code> if(Math.abs((a-b)/b) &lt; 0.00001) // ¡Todavía no es correcto! 43 49 </code></pre> 44 50 45 - <h2 id="look-out-for-edge-cases">Look out for edge cases</h2> 46 - <p>There are some important special cases where this will fail: </p> 51 + <h2 id="vigila-los-casos-lmite">Vigila los casos límite</h2> 52 + 53 + <p>Hay algunos casos especiales importantes para los que esto falla:</p> 47 54 48 55 <ul> 49 - <li>When both <code>a</code> and <code>b</code> are zero. <code>0.0/0.0</code> is “not a number”, which causes an exception on some platforms, or returns false for all comparisons. </li> 50 - <li>When only <code>b</code> is zero, the division yields “infinity”, which may also cause an exception, or is greater than epsilon even when <code>a</code> is smaller. </li> 51 - <li>It returns <code>false</code> when both <code>a</code> and <code>b</code> are very small but on opposite sides of zero, even when they’re the smallest possible non-zero numbers.</li> 56 + <li>Cuando tanto <code>a</code> como <code>b</code> son cero. <code>0.0/0.0</code> es NaN, lo que provoca una excepción en algunas plataformas o devuelve falso para todas las comparaciones.</li> 57 + <li>Cuando solo <code>b</code> es cero, la división devuelve infinito, lo que también puede causar una excepción, o es mayor que epsilon incluso cuando <code>a</code> es más pequeño.</li> 58 + <li>Devuelve «falso» cuando tanto <code>a</code> como <code>b</code> son muy pequeños pero a ambos lados del cero, incluso cuando son los números no nulos más pequeños.</li> 52 59 </ul> 53 60 54 - <p>Also, the result is not commutative (<code>nearlyEquals(a,b)</code> is not always the same as <code>nearlyEquals(b,a)</code>). To fix these problems, the code has to get a lot more complex, so we really need to put it into a function of its own:</p> 61 + <p>Además, el resultado no es conmutativo (<code>nearlyEquals(a,b)</code> no es siempre lo mismo que 62 + <code>nearlyEquals(b,a)</code>). Para solucionar estos problemas, el código tiene que ser mucho más 63 + complejo, así que necesitamos meterlo en una función:</p> 55 64 56 65 <pre><code> public static boolean nearlyEqual(float a, float b, float epsilon) 57 66 { ··· 59 68 final float absB = Math.abs(b); 60 69 final float diff = Math.abs(a - b); 61 70 62 - if (a == b) { // shortcut, handles infinities 71 + if (a == b) { // Atajo, maneja los infinitos 63 72 return true; 64 - } else if (a * b == 0) { // a or b or both are zero 65 - // relative error is not meaningful here 73 + } else if (a * b == 0) { // a o b o ambos son cero 74 + // El error relativo no es importante aquí 66 75 return diff &lt; (epsilon * epsilon); 67 - } else { // use relative error 76 + } else { // Usar el error relativo 68 77 return diff / (absA + absB) &lt; epsilon; 69 78 } 70 79 } 71 80 </code></pre> 72 81 73 - <p>This method <a href="../NearlyEqualsTest.java">passes tests</a> for many important special cases, but as you can see, it 74 - uses some quite non-obvious logic. In particular, it has to use a completely different definition of error margin 75 - when <code>a</code> or <code>b</code> is zero, because the classical definition of relative error becomes meaningless in those cases.</p> 82 + <p>Este método <a href="../NearlyEqualsTest.java">pasa las pruebas</a> para muchos casos especiales 83 + importantes, pero como puedes ver, utiliza cierta lógica no trivial. En particular, 84 + tiene que utilizar una definición totalmente distinta del margen de error cuando 85 + <code>a</code> o <code>b</code> son cero, porque la definición clásica del error relativo es inútil en 86 + esos casos.</p> 76 87 77 - <p>There are some cases where the method above still produces unexpected results (in particular, it’s much stricter when one value is nearly zero than when it is exactly zero), and some of the tests 78 - it was developed to pass probably specify behaviour that is not appropriate for some applications. Before using it, make sure it’s appropriate for your application!</p> 88 + <p>Hay algunos casos en los que el método de arriba todavía produce resultados inesperados 89 + (concretamente, es mucho más estricto cuando un valor es casi cero que cuando es 90 + exactamente cero), y algunas de esas pruebas para las que fue desarrollado probablemente 91 + especifica un comportamiento que no es apropiado para algunas aplicaciones. ¡Antes de 92 + usarlo, asegúrate de que es adecuado para tu aplicación!</p> 93 + 94 + <h2 id="comparando-valores-de-punto-flotante-como-enteros">Comparando valores de punto flotante como enteros</h2> 79 95 80 - <h2 id="comparing-floating-point-values-as-integers">Comparing floating-point values as integers</h2> 81 - <p>There is an alternative to heaping conceptual complexity onto such an apparently simple task: instead of comparing <code>a</code> and <code>b</code> as <a href="http://en.wikipedia.org/wiki/Real_numbers">real numbers</a>, we can think about them as discrete steps and define the error margin as the maximum number of possible floating-point values between the two values. </p> 96 + <p>Hay una alternativa a aplicar toda esta complejidad conceptual a una tarea aparentemente 97 + tan sencilla: en lugar de comparar <code>a</code> y <code>b</code> como <a href="http://es.wikipedia.org/wiki/N%C3%BAmero_real">números 98 + reales</a>, podemos concebirlos como pasos 99 + discretos y definir el margen de error como el número máximo de valores de punto flotante 100 + posibles entre esos dos números.</p> 82 101 83 - <p>This is conceptually very clear and easy and has the advantage of implicitly scaling the relative error margin with the magnitude of the values. Technically, it’s a bit more complex, but not as much as you might think, because IEEE 754 floats are designed to maintain their order when their bit patterns are interpreted as integers.</p> 102 + <p>Esto es conceptualmente muy evidente y fácil y tiene la ventaja de que escala 103 + implícitamente el margen de error relativo con la magnitud de los valores. 104 + Técnicamente es un poco más complejo, pero no mucho más de lo que puedas pensar, 105 + porque los números del IEEE 754 están diseñados para mantener su orden cuando 106 + sus secuencias de bits se interpretan como enteros.</p> 84 107 85 - <p>However, this method does require the programming language to support conversion between floating-point values and integer bit patterns. Read the <a href="/references/">Comparing floating-point numbers</a> paper for more details.</p> 108 + <p>Sin embargo, este método requiere que el lenguaje de programación soporte conversión 109 + entre valores de punto flotante y secuencias de bits enteras. Lee el artículo en 110 + inglés <a href="/references/">Comparing floating-point numbers</a> para más detalles.</p> 86 111 87 112 <g:plusone href="http://puntoflotante.org/"></g:plusone> 88 113 <div id="license">
+19 -23
errors/propagation/index.html
··· 2 2 <html lang="es"> 3 3 <head> 4 4 <meta charset="utf-8"> 5 - <title>La Guía del Punto Flotante - Error Propagation</title> 5 + <title>La Guía del Punto Flotante - Propagación del error</title> 6 6 7 7 <meta name="generator" content="nanoc 3.1.2"> 8 8 9 - <meta name="Description" content="Explanations about propagation of errors in floating-point math."> 9 + <meta name="Description" content="Explicaciones sobre la propagación de errores en aritmética de punto flotante"> 10 10 11 11 <link rel="stylesheet" type="text/css" href="/style.css" media="screen"> 12 12 <link rel="shortcut icon" href="/favicon.ico" type="image/vnd.microsoft.icon"> ··· 14 14 </head> 15 15 <body> 16 16 <div id="main"> 17 - <h1>Error Propagation</h1> 18 - <p>While the errors in single <a href="/formats/fp/">floating-point numbers</a> are very small, even simple calculations on them 19 - can contain pitfalls that increase the error in the result way beyond just having the individual 20 - errors “add up”.</p> 17 + <h1>Propagación del error</h1> 18 + <p>Aunque los errores en <a href="/formats/fp/">números de punto flotante</a> aislados son muy pequeños, 19 + operaciones simples con ellos pueden tener problemas e incrementar el error del resultado 20 + más de lo que se esperaría «sumando» los errores individuales.</p> 21 21 22 - <p>In general:</p> 22 + <p>En general:</p> 23 23 24 24 <ul> 25 - <li>Multiplication and division are “safe” operations</li> 26 - <li>Addition and subtraction are dangerous, because when numbers of different magnitudes are involved, 27 - digits of the smaller-magnitude number are lost.</li> 28 - <li>This loss of digits can be inevitable and benign (when the lost digits also insignificant for 29 - the final result) or catastrophic (when the loss is magnified and distorts the result strongly).</li> 30 - <li>The more calculations are done (especially when they form an iterative algorithm) the more important 31 - it is to consider this kind of problem.</li> 32 - <li>A method of calculation can be <em>stable</em> (meaning that it tends to reduce rounding errors) 33 - or <em>unstable</em> (meaning that rounding errors are magnified). Very often, there are both stable 34 - and unstable solutions for a problem.</li> 25 + <li>La multiplicación y la división son operaciones «seguras».</li> 26 + <li>La suma y la resta son peligrosas, porque cuando hay involucrados números de diferentes órdenes de magnitud, los dígitos del más pequeño se pierden.</li> 27 + <li>Esta pérdida de dígitos puede ser inevitable y benigna (cuando los dígitos perdidos son también insignificantes para el resultado final) o catastrófica (cuando la pérdida se amplifica y distorsiona el resultado fuertemente).</li> 28 + <li>Cuantas más operaciones se hagan (especialmente cuando forman parte de un algoritmo iterativo) más importante es considerar este problema.</li> 29 + <li>Un método de cálculo puede ser <em>estable</em> (tiende a reducir los errores de redondeo) o <em>inestable</em> (los errores de redondeo se amplifican). A menudo, hay soluciones estables e inestables a un problema.</li> 35 30 </ul> 36 31 37 - <p>There is an entire sub-field of mathematics (in <a href="http://en.wikipedia.org/wiki/Numerical_analysis">numerical analysis</a>) devoted to studying the numerical stability 38 - of algorithms. For doing complex calculations involving floating-point numbers, it is absolutely 39 - necessary to have some understanding of this discipline.</p> 32 + <p>Hay un área entera de las matemáticas (el <a href="http://es.wikipedia.org/wiki/An%C3%A1lisis_num%C3%A9rico">análisis 33 + numérico</a>) dedicada a estudiar la 34 + estabilidad numérica de los algoritmos. Para hacer cálculos complejos utilizando números de punto 35 + flotante, es absolutamente necesario tener ciertos conocimientos en esta materia.</p> 40 36 41 - <p>The article <a href="/references/">What Every Computer Scientist Should Know About Floating-Point Arithmetic</a> gives a detailed introduction, 42 - and served as an inspiration for creating this website, mainly due to being a bit too detailed and 43 - intimidating to programmers without a scientific background.</p> 37 + <p>Este artículo en inglés <a href="/references/">What Every Computer Scientist Should Know About Floating-Point Arithmetic</a> 38 + da una introducción detallada, y sirvió de inspiración para esta web, principalmente por el hecho 39 + de que era demasiado minucioso y un poco intimidante para programadores sin una formación científica.</p> 44 40 45 41 <g:plusone href="http://puntoflotante.org/"></g:plusone> 46 42 <div id="license">
+2 -2
style.css
··· 2 2 font-family: Helvetica, Arial, sans-serif; 3 3 } 4 4 5 - pre, code, tt{ 6 - font-family: Courier, serif; 5 + pre, code, tt { 6 + font-family: Courier, monospace; 7 7 } 8 8 9 9 body {