I have been working on a project with a lot of numbers inserted in a database table. Now that I finished the code, I was checking the values for errors and I noticed my value 3075277 would transform in 3075280 when inserted in the db and 3075255 would be 3075260.
The colummn type is Float. What should I change to disable the rounding? This one doesn't even have decimals numbers, why would it round like that? I use the default options, only changed collation to utf8_general_ci and change the type to varchar and lenght in some and float in others.
This issue is with MySQL, not Phpmyadmin.
FLOAT has 6-7 significant digits of precision, as you are seeing with the mangled values. By "significant digits", I mean starting anywhere:
1234567xxxx.
12345.67xxx
1.234567xxx
0.0000001234567xxx
That is the xxx is likely to be zeros or some kind of 'noise', not the original value you put into the column.
DOUBLE gives you about 16 significant digits.
DECIMAL(9,0) gives you 9 digits to the left of the decimal point, none afterwards. Sort of like INT.
DECIMAL(9,4) gives you 5 (9-4) digits to the left of the point; 4 afterwards.
What kinds of numbers are you storing? Money? Scientific measurements? Astronomical distances? DT's wealth?
Now you are using FLOAT type but getting error because you are saving big decimal number in the database. You should go for DOUBLE.
Although FLOAT and DOUBLE are similar because they store the value in approximate value, but that DOUBLE is 8-bytes, and FLOAT is 4-bytes.
A FLOAT is for single-precision, while a DOUBLE is for double-precision numbers.
MySQL uses four bytes for single-precision values and eight bytes for double-precision values.
There is a big difference from floating point numbers and decimal (numeric) numbers, which you can use with the DECIMAL data type. This is used to store exact numeric data values, unlike floating point numbers, where it is important to preserve exact precision, for example with monetary data.
So as in your case, for larger numbers you would want DOUBLE instead of FLOAT.
Related
How to turn off the default conversion of numbers to scientific notation. When importing from an excel file, large numbers are automatically converted to scientific notation (3.5868405364945E+14 it should be:358684053649447).Is there any option to turn off conversion in PhpExcel?
Or reverse conversions from PHP? When I trying to use printf,
printf("%d", "3.5868405364945E+14"); // 358684053649450 wrong value
final number is inaccurate.
Sorry, you'll never get the full value again, it's been already rounded, because your number has 16 digits and 15 digits is the limit for numbers in Excel.
It happens at the entry point, when you enter a number that excedes 15 digits. EXcel will round it, modifying your entry forever.
It's similar as storing a decimal number like 1.2 as integer, you'll loose that 0.2, no matter what you do, it will be 1 forever.
The only solution for this is (too late in your case), storing the large number as text in the first place, just adding a single quote before the number: '358684053649447 instead of 358684053649447. Excel will interpret that as string, not as number, and you'll be able to save numbers higher than 15 digits.
Here is my table:
Let us suppose I want my account balance to be:
0.4729472846758294728572
So I tried to set it to it but it keeps cutting it off and rounding up.
How can I stop this behavior?
FLOAT values are approximate:
The FLOAT and DOUBLE types represent approximate numeric data values.
If you need arbitrary precision you can use a DECIMAL column instead, e.g. DECIMAL(25, 20). In this case you'll get 5 digits before the decimal and 20 after.
MySQL permits a nonstandard syntax: FLOAT(M,D) or REAL(M,D) or DOUBLE PRECISION(M,D). Here, (M,D) means than values can be stored with up to M digits in total, of which D digits may be after the decimal point. For example, a column defined as FLOAT(7,4) will look like -999.9999 when displayed. MySQL performs rounding when storing values, so if you insert 999.00009 into a FLOAT(7,4) column, the approximate result is 999.0001.
see here:https://dev.mysql.com/doc/refman/5.7/en/floating-point-types.html,
http://code.rohitink.com/2013/06/12/mysql-integer-float-decimal-data-types-differences/
I'm trying to understand how float are stored in SolR.
I have a delta between the float value in PHP (32-bit) and the stored one in SolR.
I've searched in the documentation, "Field Types Included with SolR" :
https://cwiki.apache.org/confluence/display/solr/Field+Types+Included+with+Solr
And found for TrieFloatField:
Floating point field (32-bit IEEE floating point). precisionStep="0"
enables efficient numeric sorting and minimizes index size;
precisionStep="8" (the default) enables efficient range queries.
But I don't know how to estimate what will be the stored value.
Here are some tests I've made.
The value I've tried to insert in the float field and the result:
ok: 2097151.1
ko: 2097152.1 -> 2097152
ko: 20971521 -> 20971520
ok: 16777216
ko: 16777217 -> 16777216
ko: 4294967296 -> 4294967300
ok: 4294967300
ko: 4294967301 -> 4294967300
I don't understand which constraint is used, it is not rounded.
Maybe it is a binary constraint, because it looks like it is rounded to fit powers of 2.
https://en.wikipedia.org/wiki/Power_of_two#The_first_96_powers_of_two
2^21 = 2,097,152
2^24 = 16,777,216
2^32 = 4,294,967,296
As you can see, these values are close the the ones stored by SolR.
Does someone have an idea how SolR stores float?
And how to evaluate it with PHP?
Thanks.
As you've mentioned, it's a 32 bit floating point number. A 32-bit floating point number can't represent all the values between 0 and 2^32 exactly, so there will be inaccuracies and numbers that can't be represented using those bits.
You can use a converter like IEEE754 Floating Point Conversion to test the values you've included, and they all convert to what you're getting back from Solr.
Floating point numbers are not exact, and aren't magic - there's still just 2^32 distinct values available, so when you're trying to store values that don't map exactly onto the possible values that a 32 bit FP can represent, you'll get inaccuracies.
Doubles were introduced to have more accuracy (64-bit vs 32-bit), and you can use doubles in Solr by using a TrieDoubleField instead.
Another option, depending on what you need, is to use a long field instead, and multiplying by 10 or 100 when storing a value and dividing the value on the way out. That will allow you to exactly represent a decimal number with two digits after the dot.
Apparently, the most secure way to compare floats is to use pack().
Pack data into binary string to securely compare two floats.
http://php.net/manual/en/language.types.float.php#119860
So, as an alternative to using
$float1 === $float2
one could use
pack('f', $float1) === pack ('f', $float2)
with a big footnote that one should really remember that one is reducing your accuracy of the comparison. AFAIK is this the only way (apart from epsilon methods) to securely compare two floats.
In my php script I do a calculation of entries from a MySQL db. The concerning fields in the db are defined as decimal(10,3). It's an accounting plattform where I have to check if in every entry debit = credit.
I do this with the following operation:
$sumupNet = 0;
$sumup = 0;
foreach($val['Record'] as $subkey => $subval)
{
$sumupNet = $sumupNet + $subval['lc_amount_net'];
$sumup = $sumup + $subval['lc_amount_debit'] - $subval['lc_amount_credit'];
}
Now we say every entry is correkt, then $sumupNet and $sumup results in 0. In most cases, this works. But in some cases the result is something like this: -1.4432899320127E-15 or this -8.8817841970013E-15. If I calculate this values manually, the result is 0. I guess (not sure) that the above results are numbers near 0 and are outputted in the form of exponential.
So I think I have to convert something or my calculation is wrong. But what? I tried floatval() at some points but didn't work. If anybody has a hint, I thank you very much.
You're getting this because you are doing math with floating-point values. Read some theory about it.
You really don't want to calculate money like that as you might get weird rounding problems that you can't really do anything to fix.
For PHP, there are plenty of libraries that help you evade the problem, such as BC Math, or GMP.
Other solution would be to calculate all of the values using the smallest monetary value that the currency has (like cents) so you are always using integers.
These are rounding problems. These are perfectly normal when we are talking about floats. To give you an everyday example,
1/3 = 0.3333333333333333...333333333...3333...
Reason: 10 is relative prime with 3. You might wonder where is 10 coming from. We are using 10-base for numbers, that is, whenever we speak about a number, its digits represent 10-base exponential values. The computer works with binary numbers, that is, 2-base numbers. This means that division with such numbers often result in endless sequences of digits. For instance, 1/3 as a binary number looks like this:
0.010101010101010101010101010101010101010101010101010101...
Decimal types are representing decimal numbers, that is, 10-base numbers. You use three digits for the part after the . Let's supose your number ends like this:
.xyz
this means:
xyz / 1000
However, 1000 can be divided with the following prime numbers:
2 and 5.
Since 5 is relative prime with 2, whenever you are representing the result of a division by 5 as a binary number, there is a potential that the result will be an endless cycle of digits. 1/5 as a binary number looks like this:
0.0011001100110011001100110011001100110011001100110011...
Since a computer cannot store endless digits, it has to round the number, that is, find a number close to its value which can be represented in an easier manner. If the number a is rounded to b and the two numbers are not equal, then a certain amount of precision is lost and this is the reason of the bug you have mentioned.
You can solve the problem as follows: when you select the values from the database, multiply them by 1000 (thus, converting them into integers) and then check the operations. At the end, divide by 1000.
I am entering '35444650.00' as a float into my MySQL and it keeps reformatting to 35444648.00, any help welcome...
Floats only have a certain level of precision, you may be going beyond how precise a float data type can be. Try using a DOUBLE instead.
A float has 6 digits of precision. Use a double to get 15 or switch to a numeric(x,y). If you're interested, check out the storage requirements for MySQL for the different data types.
The MySQL manual claims that FLOAT, REAL, and DOUBLE PRECISION fields stores values as approximate and INTEGER, SMALLINT, DECIMAL, and NUMERIC fields stores values as exact.
I think best bet to overcome this precision issue is to use decimal.
Reference: http://dev.mysql.com/doc/refman/5.1/en/numeric-types.html
A higher precision alternative to float is DOUBLE. But looking at the example, I think the DECIMAL datatype might come in handy if the number of digits required after zero is small (around 2-4) and the number of digits before decimal is also small (around 10-12).
You are going past the level of precision possible. You need to define the float with more precision, i.e. "FLOAT(10,5)" would mean a float that can have 10 digits total with up to five after the decimal point.