Make writing a habit together! This is the fifth day of my participation in the “Gold Digging Day New Plan · April More text Challenge”. Click here for more details.

Start with a practical example

Suppose you develop a background system that does some operations on amounts. For example, the minimum accuracy is the cent, which is a penny.

So we can stipulate that 1 represents one point, 10 represents ten cents, and of course 100 represents one dollar.

At this point, 0.1 yuan can be expressed as a whole number of 10.

This means that it is perfectly possible to store a decimal value in an integer variable.

Why use itThe integerTo storeThe decimal

Because the floating-point numbers that come with computers today are inexact. This has to do with how floating-point numbers are stored. This is not the main content of this article. So I won’t go into details here.

With the twoThe integerTo represent aThe decimal

Since floating point numbers are not possible, use two integers to represent any rational number. This is the concept of fractions:

  • Numerator: an arbitrary integer (not beyond what a computer can represent)
  • Denominator: an arbitrary integer (no more than a computer can represent)

Example code (Golang) :

type MyNumber struct {
    Fenzi int64 / / molecular
    Fenmu int64 / / the denominator
}
Copy the code

In the above code, if we want to express 1/31/31/3, then

var n = MyNumber{
    Fenzi : 1,
    Fenmu : 3,}Copy the code

In this way, any rational number can be represented as long as it does not exceed the int64 range.

But here’s the problem:

  • How do you add, subtract, multiply and divide?
  • How do you derive numbers that a regular person can understand?

The answer is to do it yourself.

Here’s an example of addition (review elementary school math) :


x / y + a / b = ( x b + a y ) / y b x/y + a/b = (xb + ay)/yb

// myNumber = myNumber + other
/ / add
func (myNumber *MyNumber) Add (other *MyNumber) {
    newFenzi := myNumber.Fenzi * other.Fenmu + myNumber.Fenmu * other.Fenzi
    newFenmu := myNumber.Fenmu * other.Fenmu
    myNumber.Fenzi = newFenzi
    myNumber.Fenmu = newFenmu
}
Copy the code

So the other operations what with the same above, with primary school math knowledge on the line.

Can we do this? Of course we can.

However, this is somewhat similar to BigDecimal, which is large numbers.

Note: The real big numbers can go beyond INT64, and the above implementation is based on INT64.

Let’s start with fixed point numbers

The fixed-point number itself can be of type INT32 or int64, depending on what range of numbers your system needs.

Yes, fixed point numbers themselves are not BigDecimal and cannot represent arbitrary rational numbers; fixed point numbers are bounded.

Here’s an example:

Int26_6: The intrinsic type is int32, except that the first 26 bits are used to store the integer part and the last 6 bits are used to store the decimal part.

So how to store it, for example:


1.25 = 1 + 1 / 4 1.25 = 1 + 1/4

As above, we split 1.25 into 1 and 1/4 parts.

1, we use 1<<6 = 64. 1/4, let’s say 1<<4 = 16. 1+1/4, of course, is the sum of the above two: 1<<6 +1 <<4 = 64 + 16 = 80.

In binary:

01 0000 0000 0000 0000 0000 0000 | 0000 01

Notice the vertical line above, which represents the decimal point between the whole number and the decimal number.

There’s a problem here, the whole integer part is easy to understand, the lowest part is 1, so the whole integer part is 1.

How about the decimal part:

Why is 010,000 1/41/41/4?

Let’s see what 010000 means: 16.

And four 16s are exactly 64, remember, 64 in our algorithm, is the integer 1.

Let’s also calculate the sum of four 010,000 in binary:

010000 + 010000 + 010000 + 010000 = 1000000

And 1,000,000, in our algorithm, is exactly the integer 1.

Int26_6 is compatible with integer addition and subtraction without modification.

But multiplication and division don’t work. Here is not a detailed explanation, interested can go online to check, but also their derivation.

The benefits of using fixed-point numbers

  • Precise (especially when it comes to amounts, which of course are best with BigDecimal schemes)
  • Multi-system synchronization (if you’ve ever played a game, you know)
  • More CPU efficient than floating-point calculations