2

I have an app that getting Ethereum balance by address. The app receives balance from API and then puts it to the database. Balance comes in hex-integer:

$balance = $response->getBody(); //0x1e1e83d93bb6ebb88bbaf

Then I convert it to the WEI integer:

$hexInt = BC::hexdec($balance); // WEI "2275742359981542120930223"

And then I need to Convert WEI to ETH:

return $balance / '1000000000000000000';

If calculate it, it will be 2275742.359981542120930223, but PHP converts it to 2275742.3599815. As you see, php rounds this number after division. Why? And how can I get right result?

Alexxosipov
  • 1,215
  • 4
  • 19
  • 45
  • try putting this at the start of your script ```ini_set('precision', 32); // your precision``` – klido Dec 10 '19 at 17:47
  • Possibly also https://stackoverflow.com/questions/17218312/how-do-i-get-a-float-value-when-dividing-two-integers-php and https://stackoverflow.com/questions/20244762/php-division-results-in-automatically-rounded-up-number – Patrick Q Dec 10 '19 at 17:48
  • 1
    What's the BC in your BC::hexdec? Seems like you might want to use a BC function for your division like bcdiv()? – khartnett Dec 10 '19 at 18:44
  • @khartnett yes, this is https://github.com/krowinski/bcmath-extended – Alexxosipov Dec 10 '19 at 19:04
  • It doesn't round the value to `2275742.3599815`, it only displays it like this. It probably still rounds it to some value that is different than the value you expect, if that value cannot be represented using the floating point standard. – axiac Dec 10 '19 at 20:24

2 Answers2

1

This happens because of the implicit casts. The division returns a float. Floats are not exact values. They have a precision. You can use number_format() to specify the amount of decimals/precision for output, but the float might not provide the necessary precision. Here are ini options for it.

One solution is using bcdiv() with the expected precision. Or you write your own formatting method using string functions:

$balance = '2275742359981542120930223';

$result = $balance / '1000000000000000000';
var_dump($result);
var_dump(number_format($result, 18, '.', ''));

var_dump(bcdiv($balance, '1000000000000000000', 18));

function formatETH(string $value, int $factor = 18) {
    return substr($value, 0, -$factor).'.'.substr($value, -$factor);
}
var_dump(formatETH($balance));

Output:

float(2275742.3599815)
string(26) "2275742.359981541987508535"
string(26) "2275742.359981542120930223"
string(26) "2275742.359981542120930223"
ThW
  • 19,120
  • 3
  • 22
  • 44
  • Yes, already tested it. But this is not what I need. What should I do if I need to get the right number here? As it comes here: http://eth-converter.com – Alexxosipov Dec 10 '19 at 17:56
0

Since your dealing with big numbers, and using https://github.com/krowinski/bcmath-extended you can use the BC function for division. That bcmath-extended has a wrapper for it (bcdiv), so try:

return BC::div($balance, '1000000000000000000');
khartnett
  • 831
  • 4
  • 14