Reputation: 1
I'm trying to make a migrate that changes the column type from float to double, because the float type rounds off some values in the database, such as:
posted value: 23337840
value in database with column type float: 23337800
posted value: 23337870
value in database with column type float: 3337900
When I run the migrate to double these values are corrected to the correct one, with due precision, however values like 1 trillion are wrong.
value in column in float type: 1000000000000
value in column in double type: 999999995904
Note: When a new insert is made in the database with the column in double type with a value of 1 trillion, the value is correct. The error only occurs when a value is migrated from float to double.
Does anyone know why this occurs since the double should accept larger values? And what way can it be done so that these values already in the database remain correct?
Upvotes: 0
Views: 657
Reputation: 114188
A MySQL FLOAT
database column stores (by default) 32-bit single precision floats. These values have limited precision which becomes most obvious for very small or very large numbers. For example, these are the available 32-bit floating point values closest to 1,000,000,000,000: (with their respective difference)
999999799296.0 # -200,704
999999864832.0 # -135,168
999999930368.0 # -69,632
999999995904.0 # -4,096
1000000061440.0 # +61,440
1000000126976.0 # +126,976
1000000192512.0 # +192,512
If you have a value in-between, it will be converted to the closest float available. Attempting to store the integer 1,000,000,000,000 as a 32-bit float will actually store 999,999,995,904.0 because that's the closest value available, "only" off by 4,096.
The values FLOAT
can represent is a subset of the values DOUBLE
can represent. Which means that converting a column from FLOAT
to DOUBLE
is a lossless operation. There's no further precision loss, its numeric value won't change. However, there's no way to reconstruct the original value from the 32-bit float, i.e. converting 999,999,995,904.0 from FLOAT to DOUBLE will still be 999,999,995,904.0.
Storing new values into a DOUBLE column do benefit from the higher precision. That's why you can have 1,000,000,000,000.0 in your DOUBLE
column.
Note that floats in Ruby are 64 bit nowadays, i.e. Ruby's Float
corresponds to MySQL's DOUBLE
.
Upvotes: 1