Рубрики
Uncategorized

Анализ проблем расчета точности PHP

Автор оригинала: David Wong.

PHP

var_dump(intval(0.58 * 100));

Правильный результат-57, а не 58.

Операции с плавающей запятой

На самом деле эти результаты не являются языковыми ошибками, а связаны с принципом реализации языка. Все номера JS унифицированы как число, включая формирование. На самом деле, все они являются двойными типами.

PHP различает int и float. Независимо от того, на каком языке, пока используются операции с плавающей запятой, существуют аналогичные проблемы, на которые мы должны обращать внимание при их использовании.

Пояснение: Если вы используете PHP +-*/для вычисления чисел с плавающей запятой, вы можете столкнуться с некоторыми ошибками в вычислениях, такими как echo intval (0,58*100) выше; он будет печатать 57 вместо 58, что на самом деле является ошибкой, из-за которой нижний двоичный файл компьютера не может точно представлять числа с плавающей запятой. Это межъязыковое, и я также сталкиваюсь с этим с python. Проблема. Таким образом, в основном большинство языков предоставляют библиотеку классов или библиотеку функций для точного вычисления. Например, в PHP есть библиотека высокоточных функций BC. Позже я представлю некоторые часто используемые высокоточные функции BC.

Вернемся к вопросу 57,58 выше.

Почему вывод 57? Ошибка PHP?

Чтобы понять это, сначала нам нужно знать представление чисел с плавающей запятой (IEEE 754).:

  • Числа с плавающей запятой, например, 64-разрядной длины (двойная точность), представлены 1-битными символьными битами (E), 11 экспоненциальными битами (Q), 52-битной мантиссой (M).
  • Бит символа: Старший бит представляет положительные и отрицательные данные, 0 представляет положительное число, а 1 представляет отрицательное число.
  • Экспоненциальные биты: Мощность данных в нижней части 2 представлена кодом смещения.
  • Число: Значимое число после десятичной точки данных.

Ключевым моментом здесь является представление десятичной дроби в двоичной системе. Вы можете рассказать Байду о том, как десятичная дробь выражается в двоичной системе. Я не буду повторять это здесь. Наш ключевой момент состоит в том, чтобы понять, что 0,58-это бесконечное значение для двоичной системы (приведенное ниже число опускает подразумеваемый 1)..

Двоичное представление 0,58 в основном (52 бита) 00101000111011100001011011011010101110000101101000101010101011110100011110,57. Двоичное представление 0.58 в основном (52 бита) 0010001111010111000010110100011110.11110, и двоичное представление обоих: www.jb51.net если только вычисляется по 52 битам.

0,58 – > 0,579999999999999999999960,57 – > 0,569999999999999999999999 что касается конкретного умножения с плавающей запятой 0,58 * 100, мы не считаем, что подробно, интересно можно увидеть (с плавающей запятой), мы расплывчаты с точки зрения ментальной арифметики..999999999

Затем вы вводите его, естественно, это 57.

Итак, ключ к этой проблеме заключается в следующем: “Кажется, что у вас бесконечные десятичные числа, но в двоичном представлении компьютера у вас бесконечные десятичные числа.”

Так что не думайте, что это ошибка в PHP больше. Вот что это такое..

PHP с плавающей запятой в +-*%/Существует неточная проблема

Продолжайте просматривать фрагмент кода:

$a = 0.1;
$b = 0.7;
var_dump(($a + $b) == 0.8); // false

Печатное значение-логическое значение false

Почему? Руководство по PHP содержит следующие предупреждения для чисел с плавающей запятой:

Предупреждение

Точность с плавающей Запятой

Очевидно, что простые десятичные дроби, такие как 0,1 или 0,7, не могут быть преобразованы во внутренние двоичные форматы без потери некоторой точности. Это может привести к запутанным результатам: этаж ((0.1 + 0.7) * 10), например, обычно возвращает 7 вместо 8, как ожидалось, потому что внутреннее представление результата на самом деле похоже на 7.99999999….

Это связано с тем, что невозможно точно выразить определенные десятичные дроби бесконечными цифрами. Например, одна треть десятичной системы становится 0,3333333….

Поэтому никогда не верьте, что результат с плавающей запятой точен до последней точки, и никогда не сравнивайте, равны ли два числа с плавающей запятой. Если действительно требуется более высокая точность, следует использовать математические функции произвольной точности или функции GMP.

Поэтому приведенную выше формулу следует переписать следующим образом

$a = 0.1;
$b = 0.7;
var_dump(bcadd($a,$b,2) == 0.8); // true

Обычно используемые высокоточные функции заключаются в следующем:

  • Bcadd – Добавляет две цифры высокой точности
  • Bccomp – Сравнение двух высокоточных чисел, возврат – 1, 0, 1
  • Bcdiv – деление двух цифр высокой точности
  • Bcmod-Поиск Высокоточного Цифрового Остатка
  • Bcmul – Умножение двух чисел высокой точности
  • Bcpow-Поиск Высокоточного Цифрового Умножителя
  • Bcpowmod – высокоточный цифровой модуль умножения, очень распространенный в теории чисел
  • Масштаб BC — Настройте десятичное число по умолчанию, которое эквивалентно “масштаб=” в Linux BC
  • Bcsqrt-Поиск Цифровых Квадратных Корней Высокой Точности
  • Bcsub – Вычитание Двух Чисел Высокой Точности

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

/**
* Comparison of Two High Precision Numbers
* 
* @access global
* @param float $left
* @param float $right
*@ The exact decimal point number of param int $scale
* 
*@ Return int $left== $right returns 0 | $left < $right returns - 1 | $left > $right returns 1
*/
var_dump(bccomp($left=4.45, $right=5.54, 2));
// -1
/**
* Addition of Two High Precision Numbers
* 
* @access global
* @param float $left
* @param float $right
*@ The exact decimal point number of param int $scale
* 
* @return string 
*/
var_dump(bcadd($left=1.0321456, $right=0.0243456, 2));
//1.05
/**
* Subtraction of Two High Precision Numbers
* 
* @access global
* @param float $left
* @param float $right
*@ The exact decimal point number of param int $scale
* 
* @return string 
*/
var_dump(bcsub($left=1.0321456, $right=3.0123456, 2));
//-1.98
/**
* Two High Precision Dividing Numbers
* 
* @access global
* @param float $left
* @param float $right
*@ The exact decimal point number of param int $scale
* 
* @return string 
*/
var_dump(bcdiv($left=6, $right=5, 2));
//1.20
/**
* Multiplication of Two High Precision Numbers
* 
* @access global
* @param float $left
* @param float $right
*@ The exact decimal point number of param int $scale
* 
* @return string 
*/
var_dump(bcmul($left=3.1415926, $right=2.4569874566, 2));
//7.71
/**
* Setting the decimal point number of BC function
* 
* @access global
*@ The exact decimal point number of param int $scale
* 
* @return void 
*/ 
bcscale(3);
var_dump(bcdiv('105', '6.55957')); 
//php7.1 16

Выше приведено все содержание этой статьи. Я надеюсь, что это будет полезно для изучения каждого, и я надеюсь, что вы будете больше поддерживать разработчика.