Convert IEEE 754 to decimal floating point - php

I have what I think it is an IEEE754 with single or double precision (not sure) and I'd like to convert it to decimal on PHP.
Given 4 hex value (which might be in little endian format, so basically reversed order) 4A,5B,1B,05 I need to convert it to a decimal value which I know will be very close to 4724.50073.
I've tried some online converters but they are far from the expected result so I'm clearly missing something.
If I echo 0x4A; I get 74 and the others are 91, 27 and 5. Not sure where to take it from here...

To convert it to float, use unpack. If the byte order is incorrect, you'll have to reverse it yourself before unpacking. 4 bytes (32 bits) usually means it's a float, 8 for double.
$bin = "\x4A\x5B\x1B\x05";
$a = unpack('f', strrev($bin));
echo $a[1]; // 3589825.25
I don't see any way how this maps to 4724.50073 directly tho. Without any more test data or manufacturer's manual this question is not fully answerable.
Speculation: judging from the size of the coordinate it's probably some sort of projection (XYZ or mercator) which can then be converted to WGS84 or whatever you need. Unfortunately there's no way to check since you haven't provided both latitude and longitude.

Related

Calculate and display up to 18 decimal places in PHP with precision

I'm new to math in PHP. I'm working on calculating cryptocurrencies that have up to 18 decimal places. What is the best way to calculate this precisely in PHP? Most answers on SO are for other coding languages and about rounding.
For example, when I do the below, I don't get 0.000000000000000001 as an answer.
$a= 0.000000000000000002;
$b= 0.000000000000000001;
$balance = $a - $b;
What I get is -8.0E-20 which is not 0.000000000000000001 (i think).
Also, [from here][1], it says float has a max of 14 decimal places but then it used the word "roughly."
[1]: https://www.php.net/manual/en/language.types.float.php#:~:text=The%20size%20of%20a%20float,the%2064%20bit%20IEEE%20format).
To keep your precision when displaying, you must use a Float Data type, see the floatval() function for more help.
Up to 18 places is an arbitrary amount more than the supported size, which is 14 on most machines depending on memory?
As mentioned in the comments using defined base units would solve the problem, to expand on that to be a more generalized solution that is more scalable, applicable to more algorithms, is to create a new class to hold this data type, dynamic float (d_float) is what I would use, cc_value = new d_float(value: int, pof10: int); cc_value * pof10; Where crypto currency value is described by a integer value that contains each digit and a second integer that can be applied to return the correct decimal value. Different base amounts could simply be extensions of the d_float class and therefore have fixed pof10 values?

phpMyAdmin Float Disable Round Number

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.

SolR float (TrieFloatField) storage limits

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.

MySQL & PHP decimal precision wrong

24151.40 - 31891.10 = -7739.699999999997
I grab these two numbers from a MySQL table with the type as decimal(14,2)
24151.40
31891.10
It is saved exactly as stated above and it echos exactly like that in PHP. But the minute I subtract the second value from the first value, I get a number -7739.699999999997 instead of -7,739.7. Why the extra precision? And where is it coming from?
From an article I wrote for Authorize.Net:
One plus one equals two, right? How about .2 plus 1.4 times 10? That equals 16, right? Not if you're doing the math with PHP (or most other programming languages):
echo floor((0.2 + 1.4) * 10); // Should be 16. But it's 15!
This is due to how floating point numbers are handled internally. They are represented with a fixed number of decimal places and can result in numbers that do not add up quite like you expect. Internally our .2 plus 1.4 times 10 example computes to roughly 15.9999999998 or so. This kind of math is fine when working with numbers that do not have to be precise like percentages. But when working with money precision matters as a penny or a dollar missing here or there adds up quickly and no one likes being on the short end of any missing money.
The BC Math Solution
Fortunately PHP offers the BC Math extension which is "for arbitrary precision mathematics PHP offers the Binary Calculator which supports numbers of any size and precision, represented as strings." In other words, you can do precise math with monetary values using this extension. The BC Math extension contains functions that allow you to perform the most common operations with precision including addition, subtraction, multiplication, and division.
A Better Example
Here's the same example as above but using the bcadd() function to do the math for us. It takes three parameters. The first two are the values we wish to add and the third is the number of decimal places we wish to be precise to. Since we're working with money we'll set the precision to be two decimal palces.
echo floor(bcadd('0.2', '1.4', 2) * 10); // It's 16 like we would expect it to be.
PHP doesn't have a decimal type like MySQL does, it uses floats; and floats are notorious for being inaccurate.
To cure this, look into number_format, e.g.:
echo number_format(24151.40 - 31891.10, 2, '.', '');
For more accurate number manipulation, you could also look at the math extensions of PHP:
http://www.php.net/manual/en/refs.math.php
This has to do with general float / double precision rates, which scientifically relates to 1.FRACTAL * 2^exponential power. Being that there's a prefix of 1, there's technically no such thing as zero, and the closest value you can obtain to 0 is 1.0 * 2 ^ -127 which is .000000[127 0s]00001
By rounding off your answer to a certain precision, the round factor will give you a more precise answer
http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_round

Float not correct in MySQL

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.

Categories