tutorial smart remix programador online español curso c++ floating-point cout cpu-registers floating-point-precision

c++ - remix - smart contracts ethereum



¿Puede modificar las variables de alguna manera? (5)

Entonces tengo una función que se ve así:

float function(){ float x = SomeValue; return x / SomeOtherValue; }

En algún punto, esta función se desborda y devuelve un valor negativo realmente grande. Para intentar localizar exactamente dónde estaba pasando esto, agregué una declaración cout para que la función se viera así:

float function(){ float x = SomeValue; cout << x; return x / SomeOtherValue; }

¡Y funcionó! Por supuesto, resolví el problema completamente usando un doble. Pero tengo curiosidad de por qué la función funcionó correctamente cuando lo presenté. ¿Es esto típico, o podría haber un error en otro lugar que me estoy perdiendo?

(Si sirve de ayuda, el valor almacenado en el flotador es solo un valor entero, y no particularmente grande. Lo puse en un flotador para evitar el lanzamiento).


Bienvenido al maravilloso mundo del punto flotante. La respuesta que obtenga probablemente dependerá del modelo de punto flotante con el que compiló el código.

Esto sucede debido a la diferencia entre la especificación IEEE y el hardware en el que se ejecuta el código. Es probable que su CPU tenga registros de coma flotante de 80 bits que se utilizan para mantener el valor flotante de 32 bits. Esto significa que hay mucha más precisión mientras el valor permanece en un registro que cuando se lo fuerza a una dirección de memoria (también conocido como ''origen'' del registro).

Cuando pasó el valor de cout el compilador tuvo que escribir el punto flotante en la memoria, y esto da como resultado una pérdida de precisión y un comportamiento interesante de los casos de desbordamiento de WRT.

Consulte la documentación de MSDN en los conmutadores de coma flotante de VC ++. Puedes intentar compilar con / fp: strict y ver qué pasa.


Como un aparte, siempre es una buena idea declarar variables inmutables usando const :

float function(){ const float x = SomeValue; cout << x; return x / SomeOtherValue; }

Entre otras cosas, esto evitará que pases involuntariamente tus variables a funciones que pueden modificarlas a través de referencias no const .


Imprimir un valor para cout no debería cambiar el valor del parámetro de ninguna manera.

Sin embargo, he visto un comportamiento similar, al agregar declaraciones de depuración provoca un cambio en el valor. En esos casos, y probablemente también este, mi conjetura fue que las declaraciones adicionales estaban causando que el optimizador del compilador se comportara de manera diferente, así que genera un código diferente para tu función.

Agregar la declaración cout significa que el valor de x se usa directamente. Sin él, el optimizador podría eliminar la variable, cambiando así el orden del cálculo y, por lo tanto, cambiando la respuesta.


No creo que la acción tenga ningún efecto sobre la variable, el problema debería ser en otro lugar.


cout provoca una referencia a la variable, que a menudo hará que el compilador fuerce su derrame en la pila.

Debido a que es un flotante, esto probablemente causa que su valor se trunque de la representación doble doble o larga que normalmente tendría.

Llamar a cualquier función (no en línea) que tome un puntero o referencia a x debería terminar causando el mismo comportamiento, pero si el compilador más tarde se vuelve más inteligente y aprende a alinearlo, serás igual de jodido :)