Entiendo que flotante es una aproximación que depende de la precisión que desee. Sin embargo, no estoy seguro de por qué convierte 6.099999904632568 en 6.1. ¿Por qué necesita redondearlo en lugar de detenerse en su máxima precisión (es decir, 6.09999990)

¿Hay alguna forma de forzar que un número se almacene con su máxima precisión sin ser redondeado?

Información de la mesa

CREATE TABLE `urls` ( `id` int(11) NOT NULL AUTO_INCREMENT, `gcloud_magnitude` float DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1193 DEFAULT CHARSET=utf8;

Código para reproducir

mysql> INSERT INTO urls (url_md5, gcloud_magnitude, created_at, updated_at) VALUES ('noop', 6.099999904632568, '2018-09-16 14:57:49', '2018-09-16 14:57:49'); Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM urls WHERE url_md5 = 'noop'\G; id: 1193 url_md5: noop gcloud_magnitude: 6.1 1 row in set (0.00 sec)

El intérprete de Ruby analiza como flotante

irb(main):004:0> Url.find_by(url_md5: 'noop').gcloud_magnitude.to_f => 6.1

0
okysabeni 16 sep. 2018 a las 19:20

3 respuestas

La mejor respuesta

El valor que ve, 6.1, es probablemente un llamado salida de ida y vuelta. Esa es la salida más corta que, cuando se analiza, recuperará el mismo valor que tenía . No todos los idiomas generan flotantes o dobles como ida y vuelta, pero algunos lo hacen, a menos que se indique explícitamente lo contrario. Supongo que Ruby es uno de ellos.

El valor 6.1, cuando se analiza como flotante, obtiene el valor exacto 6.099999904632568359375, pero el valor 6.099999904632568, cuando se analiza, obtiene exactamente el mismo valor. 6.1 es el resultado más corto que se puede generar para ese flotante en particular y cuando se vuelve a leer (analizado nuevamente), generará el mismo flotante.

3
Rudy Velthuis 17 sep. 2018 a las 16:09

Quería resumir mis hallazgos como respuesta.

Cuando guardo un valor como 6.099999904632568 en un tipo de datos flotante, MySQL lo representa como 6.1. Cuando cambio el tipo de datos a decimal with precision 64 and scale 30, el 6.099999904632568 aparece automáticamente sin que actualice el valor.

Parece que MySQL guardó la representación original del número, pero no hay forma de devolver ese valor como flotante. Cuando cambié el tipo de datos a decimal, MySQL sabe cómo representarlo correctamente y lo devuelve correctamente.

Esto es desconcertante para mí. Si MySQL conoce la representación original, ¿por qué no puedo recuperar el valor original sin que se escriba como flotante? Además, dado que 6.099999904632568 tiene una precisión superior a la que pueden manejar 4 bytes, ¿cómo almacena la representación original?

Más preguntas que no están relacionadas con esta pregunta original.

-1
okysabeni 18 sep. 2018 a las 12:55

El tipo de datos FLOAT en MySQL no tiene suficiente precisión para almacenar el valor que le dio. El tipo de datos DOUBLE puede hacerlo.

Ejemplo:

mysql> create table f ( f float, d double);

mysql> insert into f values (6.099999904632568, 6.099999904632568);

mysql> select * from f;
+------+-------------------+
| f    | d                 |
+------+-------------------+
|  6.1 | 6.099999904632568 |
+------+-------------------+

FLOAT redondea el valor a la precisión que puede almacenar. De hecho, el redondeo se produce incluso con valores con menos precisión que el valor que utilizó.

mysql> select * from f;
+---------+-------------------+
| f       | d                 |
+---------+-------------------+
|     6.1 | 6.099999904632568 |
|     6.1 |         6.0999999 |
|     6.1 |          6.099999 |
| 6.09999 |           6.09999 |
+---------+-------------------+

Simplemente no hay suficientes bits en un FLOAT de 32 bits para almacenar una precisión ilimitada. Entonces tiene que redondear el valor.

Encontrarás que también hay un límite en la precisión de un DOUBLE. Almacena valores en un formato de 64 bits.

0
Bill Karwin 16 sep. 2018 a las 17:46