Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I eliminate floating point inaccuracy when I pack and unpack a floating point number?

Tags:

perl

pack

unpack

I am packing an array of numbers to send via UDP to another piece of hardware using socket programming.

When I pack the number 12.2 and then unpack it, I get 12.199999892651. As I am working with numbers related to latitudes and longitudes, I cannot have such deviations.

This is the simple script I wrote:

use warnings;

use Time::HiRes qw (sleep);

@Data = ( 20.2, 30.23, 40.121, 1, 2, 3, 4, 6. 4, 3.2, 9.9, 0.1, 12.2, 0.99, 7.8, 999, 12.3 );

$myArr = pack('f*', @Data);

print "$myArr\n\n";

@Dec = unpack('f*',$myArr);

print "@Dec";

The output is:

20.2000007629395 30.2299995422363 40.1209983825684 1 2 3 4 6.40000009536743 3.20 000004768372 9.89999961853027 0.100000001490116 12.1999998092651 0.9900000095367 43 7.80000019073486 999 12.3000001907349

Is there any way I can control the precision?

like image 742
Asheesh Avatar asked Dec 22 '25 01:12

Asheesh


2 Answers

pack's f template is for single-precision floating point numbers, which on most platforms is good to 7 or so decimal places of accuracy. The d template offers double-precision and will be good enough for ~15 decimal places.

print unpack("f", pack("f",12.2));          # "12.1999998092651"
print unpack("d", pack("d",12.2));          # "12.2"

printf "%.20f",unpack("f", pack("f",12.2)); # "12.19999980926513671875"
printf "%.20f",unpack("d", pack("d",12.2)); # "12.19999999999999928946"
like image 70
mob Avatar answered Dec 23 '25 14:12

mob


The short answer is: don't pack these numbers as floats. You will lose accuracy due to IEEE floating point representation. Instead, convert them to "character decimals" (i.e. strings), and pack them as strings. If you really need the accuracy, and don't need to perform math operations on them, you may want to store them as strings in Perl as well.

like image 27
mwp Avatar answered Dec 23 '25 15:12

mwp



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!