4

I am having PHP calculation problems (I think - i am reasonably new to PHP).

I am using

function convertToBTCFromSatoshi($value){
    $BTC = ($value / 100000000 );
    return (float)$BTC;
}

If $value = 10000 the result is correct of "0.0001"

Yet if $value = 5000 the result is "-5.0E-5"

Any ideas please :-)

  • why the -1 ? it was a genuine question! – Ford Jul 14 '13 at 21:52
  • 1
    Please note that one should never use floating point in money calculations, as it may lose accuracy. stackoverflow.com/questions/3730019/… – Mikko Ohtamaa Jul 16 '13 at 7:11
  • 2
    This question appears to be off-topic because it is about php programming. – Stéphane Gimenez Jul 20 '13 at 18:13
8

You really should not use floating point math for precision decimal values. It is a little-regarded truth of computer programming that when you're dealing with money you should avoid the usual IEEE floating-point math like the plague.

This is the reason why Bitcoin transactions store values as 64-bit integers. Because storing them as floating point numbers is error-prone.

For example, in your interactive PHP shell you can do something like this to find out where your math begins to break:

php > echo 10000.00000001 * 2;
20000.00000002
php > echo 100000.00000001 * 2;
200000.00000002
php > echo 1000000.00000001 * 2;
2000000

I'm running 64-bit PHP, too. If you are running 32-bit PHP the situation becomes pretty dire.

The take-away here is that overall precision of floating point numbers is limited. The bigger your number, the fewer meaningful decimal places it can have.

The correct way to address this problem is to use PHP's BC Math functions. You keep your data as strings, and BCMath will let you perform arbitrary-precision computations. It isn't as fast as floating point math, but it isn't exactly slow either.

/** Convert Satoshis to a string that can be displayed to users.
 *  input: $value Integer or string that can be parsed as an int.
 *  output: string (eg: "1.00400000")
 */
function convertToBTCFromSatoshi($value){
    return bcdiv( intval($value), 100000000, 8 );
}

If you want to trim the zeros from the end of the output, you can use the trim() function:

rtrim($value, "0"); // trim zeros from the right-hand side
  • Is that really a serious risk? Are you really afraid that someone will get 1 million BTC together - to steal 1 satoshi from you? – Nick ODell Jul 20 '13 at 0:55
  • It's also about small rounding errors, and decimal values that can't be precisely expressed in binary. And don't forget, Bitcoins are meant to be infinitely divisible. It is generally accepted that the protocol can be changed to support smaller units, if required. – slashingweapon Jul 20 '13 at 2:38
3

You should use bcmath, because PHP's native calculations won't fit your needs.

1

The calculation is correct, but it becomes wrong when it shows the result to you.

Code:

function convertToBTCFromSatoshi($value) {
    $BTC = $value / 100000000 ;
    return $BTC;
}
function formatBTC($value) {
    $value = sprintf('%.8f', $value);
    $value = rtrim($value, '0') . ' BTC';
    return $value;
}
echo formatBTC(convertToBTCFromSatoshi(5000));

Outputs:

0.00005 BTC
  • works perfect! sent a small BTC Tip – Ford Jul 14 '13 at 21:19
  • The valid range for satoshis won't fit into an int on php32bit. so you need to use strings, and bcdiv, NOT native division as this answer indicates. – karimkorun Mar 12 at 14:29
0

Satoshi to BTC

(Mathematical formula: Value * 10 ^ -8):

$satoshi = 5000; //Satoshi to btc
echo number_format(($satoshi)*(pow(10, -8)), 8, '.', ''); //Returns 0.00005000

BTC to Satoshi

(Mathematical formula: Value * 10 ^ 8):

$btc = 0.00005; //Btc to satoshi
echo ($btc)*(pow(10, 8)); //Returns 5000

Explanation

pow() - Exponential expression
number_format($var, 8, '.', '') - Returns a number eight decimal places
  • The standard mathematical operators in PHP are limited by the system's build - 32 or 64bit. This means your Satoshi to BTC conversion will be wrong on a 32bit system for values larger than 2^32. It's advised to use bcmath to convert between BTC & Satoshis. I typically use GMP on the satoshi amounts after, since it's faster. – karimkorun Apr 2 '16 at 12:39
-1

Easiest way

sprintf('%.8f', $amount); // 0.00000000
  • 1
    webdev1, please use code formatting when posting code. You can click edit on your own post to see how I did it. – Nick ODell Oct 30 '14 at 15:34
-1

Since you have not picked an answer, can I suggest a function? It is sufficient to handle your BTC transactions

function btc_output($x) {
    $f = sprintf('%0.08f', $x);
    $f = rtrim($f,'0');
    $f = rtrim($f,'.');
    return $f;
} 

$v = 5000/100000000;

echo btc_output($v); // 0.00005

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.