Проблема преобразования сатоши в биткойны с помощью PHP

У меня проблемы с расчетами PHP (я думаю, что я новичок в PHP).

Я использую

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

Если $value = 10000, правильный результат "0,0001"

Но если $value = 5000, результат будет "-5.0E-5".

Любые идеи, пожалуйста :-)

почему -1? это был искренний вопрос!
Обратите внимание, что никогда не следует использовать числа с плавающей запятой в денежных расчетах, так как это может привести к потере точности. stackoverflow.com/questions/3730019/…
Этот вопрос кажется не по теме, потому что речь идет о программировании на php.

Ответы (7)

Вы действительно не должны использовать математику с плавающей запятой для точных десятичных значений. Это малоизвестная истина компьютерного программирования: когда вы имеете дело с деньгами, вам следует избегать обычной математики IEEE с плавающей запятой, как чумы.

По этой причине транзакции Биткойн хранят значения как 64-битные целые числа. Потому что хранение их в виде чисел с плавающей запятой чревато ошибками.

Например, в вашей интерактивной оболочке PHP вы можете сделать что-то вроде этого, чтобы узнать, где ваши математические вычисления начинают ломаться:

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

Я тоже использую 64-битный PHP. Если вы используете 32-битный PHP, ситуация становится довольно ужасной.

Вывод здесь заключается в том, что общая точность чисел с плавающей запятой ограничена. Чем больше ваше число, тем меньше значащих десятичных разрядов оно может иметь.

Правильный способ решить эту проблему — использовать функции PHP BC Math . Вы храните свои данные в виде строк, а BCMath позволит вам выполнять вычисления с произвольной точностью. Это не так быстро, как математика с плавающей запятой, но и не совсем медленно.

/** 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 );
}

Если вы хотите обрезать нули с конца вывода, вы можете использовать trim()функцию:

rtrim($value, "0"); // trim zeros from the right-hand side
Это действительно серьезный риск? Вы действительно боитесь, что кто-то соберет 1 миллион BTC, чтобы украсть у вас 1 сатоши?
Это также касается небольших ошибок округления и десятичных значений, которые нельзя точно выразить в двоичном виде. И не забывайте, биткойны предназначены для бесконечного деления. Принято считать, что протокол может быть изменен для поддержки меньших единиц, если это необходимо.

Вы должны использовать bcmath , потому что собственные вычисления PHP не будут соответствовать вашим потребностям.

Или GMP

Расчет правильный, но он становится неправильным, когда показывает вам результат.

Код :

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));

Выходы:

0.00005 BTC
работает идеально! отправил небольшую подсказку BTC
Допустимый диапазон для сатоши не помещается в int на php32bit. поэтому вам нужно использовать строки и bcdiv, а НЕ родное деление, как указывает этот ответ.

Сатоши к BTC

(Математическая формула: Значение * 10 ^ -8):

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

Биткойн в Сатоши

(Математическая формула: Значение * 10 ^ 8):

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

Объяснение

pow() - Exponential expression
number_format($var, 8, '.', '') - Returns a number eight decimal places
Стандартные математические операторы в PHP ограничены сборкой системы - 32 или 64 бит. Это означает, что ваше Satoshi to BTCпреобразование будет неверным в 32-битной системе для значений больше 2^32. Рекомендуется использовать bcmath для преобразования между BTC и сатоши. Я обычно использую GMP для сумм сатоши после, так как это быстрее.

Я почти уверен, что вы уже нашли ответ, но ради других. вот довольно хороший способ решить эту проблему, используя bcdiv от bcmath

(PHP 4, PHP 5, PHP 7, PHP 8) bcdiv — Разделить два числа произвольной точности Документы

$value = 5000;
$convertToBTCFromSatoshi = (function ($value): string {
  return bcdiv((string)$value, '100000000', 8);
})($value);

Самый простой способ

sprintf('%.8f', $amount); // 0.00000000
webdev1, пожалуйста, используйте форматирование кода при размещении кода. Вы можете нажать «Изменить» в своем посте, чтобы увидеть, как я это сделал.

Поскольку вы не выбрали ответ, могу ли я предложить функцию? Этого достаточно для обработки ваших транзакций BTC.

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