Pular para o conteúdo principal

General: Prevent arbitrary precision arithmetic

Demand

Some simple decimal calculations like 4.6 * 100 may lead in irregularities when dealing with numbers.

Description

During arithmetic operations like addition, subtraction, multiplication, and division, the numbers are manipulated according to the rules defined by the IEEE 754 standard. However, due to the finite precision of the representation, rounding errors may occur, leading to small discrepancies between the expected and actual results of computations. 

To prevent it we may use some libraries to prevent the problem. In Javascript and Typescript we have the BigNumbers library (and others). PHP has a built-in library for arbitrary-precision arithmetic called BCMath (Binary Calculator). Wich I reccomend. It provides functions to perform mathematical operations on numbers with arbitrary precision, including addition, subtraction, multiplication, division, and more.

Examples

PHP Sample
1: php > var_dump(floor((10*0.91597) * 1000000)/1000000);
2: float(9.159699)
3: php > var_dump(bcmul(10,0.91597, 6));
4: string(8) "9.159700"
Javascript sample
1: > (Math.floor(10 * (0.91597 * 100 	00)) / 10000).toFixed(4);
2: >- '9.1596'
3: > BigNumber(10).multipliedBy(0.91597).multipliedBy(10000).dividedBy(10000).decimalPlaces(4).toNumber()
4: >- 9.1597

Examples Explanation

In the first line we see a simple operation where we multiply 10 by 0.91597 and should yield to 9.1597 but when not using a precision arithmetic safe library (as shown at line 1) the results are inconsistent (presented in line 2). When using an assistent library (at line 3) the operation results was fixed (as shown at line 4).

When performing floating-point calculations on a computer, the numbers are typically represented in binary format using a fixed number of bits. The IEEE 754 standard is commonly used for floating-point representation, which defines formats for single precision (32 bits) and double precision (64 bits) floating-point numbers.

For example, let's consider the double-precision format, which uses 64 bits to represent a floating-point number. The binary representation consists of three parts: the sign bit, the exponent, and the significand (also known as the mantissa).

When the values 10 and 0.91597 are represented in binary floating-point format, they are approximated to fit into the available number of bits. This approximation may introduce rounding errors due to the limited precision of the representation.

For example, the number 10 in binary floating-point format might be represented as follows:

Sign bit: 0 (positive)

Exponent: 10000000010 (biased exponent, indicating 3 in binary)

Significand: 0100000000000000000000000000000000000000000000000000 (fractional part)

Similarly, the number 0.91597 may be approximated in binary floating-point format as follows:


Sign bit: 0 (positive)

Exponent: 01111111111 (biased exponent, indicating 0 in binary)

Significand: 1101011011001100001010011110101110000101000111101101 (fractional part)


Known equations with simple numbers that will result in arithmetic inaccuracy:

  • 4.6 * 100 = 459.99999999999994
  • 10 * 0.91597 = 9.159699999999999
  • If you know any other equation just like that, please, leave a comment!

    Comentários

    Postagens mais visitadas deste blog

    SQL: Naming external identification code fields at database.

    Demand Use "id_{context}" to name fields of external identification codes and "{context}_id" to internal ones. Description When creating a column in a table that reference an id (identification code) of a table located at the database you are dealing it should be named as "{Table Name}_id". When creating a column in a table that reference an id of a context external to the database you are dealing with  it should be named as "id_{Context Name}". Examples 1: CREATE TABLE customer ( 2:     id INT NOT NULL, 3:   name VARCHAR(100) NOT NULL, 4:     id_ssn COMMENT ' the United States, the Social Security number', 5:    user_id INT NULL COMMENT 'if the customer have a system login it will be refernced here', 6:      PRIMARY KEY (id), 7:     UNIQUE `uq_ssn` (`ssn`), 8:      CONSTRAINT `fk_customers_user_id_users_user_id` 9:           FOREIGN KEY (`user...

    PHP: Always use an index to add a values to an array

      Demand Always identify the array index when manipulating the array directly Description Whenever you are adding a new item to the array you must add an index so that php does not need to recalculate the size of the array to identify in which position the new content will be added. Examples 1: # Bad code: 2: do { 3: $array[] = $newItem; 4: } while(!feof($fp)); 5: 6: # Good code 7: $array = []; 8: $index = 0; 9: do { 10: $array[$index++] = $newItem; 11: } while(!feof($fp)); Examples Explanation When instantiating a new item in an array in the "bad example" php will identify that you expect the item to be added to the end of the array, since array is a primitive type and has no attributes php always needs to call a calculation function to identify the current size of the array before trying to add a new item to the end of it. By monitoring the growth of the array in an external variable and automatically reference which position will...