In f32 - Rust, the document just specifies the result of the comparison between two special numbers, however, I'm more interested in How the result will be when comparing two normal numbers. The document just refers to the IEEE 754 standard, however, I don't find any useful information in that document. I'm concerned about the case where two numbers are equivalent on Mathematical but it will be compared inequivalent in the program. So, I wonder how Rust processes the comparison between two normal numbers.

fn main() {
let a = 19.62f32;
let b = 11.62 + 8.00;
println!("{}", a==b); // false
}

There's a reason clippy has a lint for this^{[1]}. No matter which real-number-approximation you choose, comparisons involving the machine epsilon are going to appear in the recommendations.

I come to the conclusion half the problem people have with floating point numbers and computers is that our languages let us write incorrect literal values in the fist place. That is to say we can write literal values that cannot be represented in the binary floating point format. Example:

We write 0.3
We get in our variable 00111110100110011001100110011010
Which is actually the number 0.300000011920928955

Clearly our language and compiler should not let us make this error. Especially if it prioritises correctness as Rust does.

Contrast to the situation with the integers. We would not expect to get away with writing:

let x: i32 = 0.5

The compiler will complain that `0.5Â´ is not an integer.

Clearly the compiler should complain that 0.3 is not a floating point value. It cannot exist in the IEEE 754 standard or our computer.

Suggest an error message like:

let x: i32 = 0.3;
| --- ^^^ expected `f32`, found real number
| |
| expected due to this
help: consider using 0.300000011920928955

With this correction to the compiler half the complaints about floating point operations would disappear as people would immediately know what they are dealing with.

The linked article is a good suggestion for comparing two f32 numbers. However, I wonder how two numbers are compared in a traditional way(i.e. x == y or x != y).

Aside from NANs, they are simply compared as bit sequences. The problem is that these bit sequences can be slightly different from what you expect if you look at the calculations as if they were performed with real numbers.

Thanks. This is what I am asking here. Do (negative/positive)infinity numbers compare bit sequences too? Is this part documented in the IEEE 754 standard?

There are exceptions, such as comparisons between zero and negative zero. They have different binary representations but evaluate to the same value. This is mostly inconsequential in practice but it's good to know for trivia night.

I asked the question for the normalized numbers. Are comparisons of them just bit sequences comparison and where provenance in the IEEE 754 is this interpretation from?

Assuming that Rust implements IEEE-754 semantics (which is not true on some platforms), two normal f32 numbers compare equal if they correspond to the same real number, and unequal if they don't.

In your example:
19.62f32 = 10011.1001111010111000011 in binary
11.62f32 = 1011.10011110101110000101
11.62f32 + 8f32 = 10011.1001111010111000010 (the last bit of 11.62f32 got rounded off)

So 19.62f32 and 11.62f32 + 8f32 differ in the last bit, and hence they correspond to different real numbers and compare unequal.

According to your interpretation by using the binary sequences, did you mean they compare equally if their bit sequences are the same? Instead of saying they represent the same "real number"

For normal numbers that is the same thing. For zero that is not the same thing because two f32 values with different representations (+0.0 and -0.0) correspond to the same real number 0 and hence compare equal.

The actual standard is unfortunately not available freely - the IEEE charges around USD 100 for non-members to access the standard, and they are fairly vigilant about keeping unauthorized copies off the Web. That makes providing specific citations a bit challenging.

However, should you find yourself in possession of a copy - perhaps from your local library, or if you're at a university that has an IEEE membership, then through institutional access - then page 43 (section 5.11) describes equality in general. Quote: "Infinite operands of the same sign shall compare equal." The IEEE 794-2019 specification does not elaborate further; how those comparisons are performed is up to the implementation.

Rust generally delegates that to the underlying hardware, where possible, but even where it must be emulated, you can assume that two equations producing infinities will produce equal infinities if they have the same sign, and unequal infinities if the signs differ.

Your answer is about Infinity, but how about the numbers that are not NAN, ZERO, and INFINITY? How do they compare? It seems that most answers say that they are compared by using bit sequences.

IEEE 794-2019 does not explicitly define how comparison should work, only that it should have specific properties. From s. 5.11:

Four mutually exclusive relations are possible: less than, equal, greater than, and unordered; unordered arises when at least one operand is a NaN. Every NaN shall compare unordered with everything, including itself. Comparisons shall ignore the sign of zero (so +0 = -0). Infinite operands of the same sign shall compare equal.

Language standards shall define the comparison predicates in Tables 5.1 and 5.2. These predicates deliver a true-false response and are defined in pairs. Each predicate is true if and only if any of its indicated relations is true. Applying a prefix such as NOT to negate a predicate reverses the true-false sense of its associated entries, but does not change whether unordered relations signal an invalid operation exception.

The referenced tables go on to define signalling and non-signalling operations in terms of equal, greater than, less than, or unordered, in various combinations, as well as constraining that certain pairs of operations must be negations of one another. I'm not going to transcribe them here, as they're fairly obvious.

As far as formats go, the section is surprisingly terse:

For every supported arithmetic format, it shall be possible to compare one floating-point datum to another in that format (see 5.6.1). Additionally, it shall be possible to compare one floating-point datum to another in a different format as long as the operands' formats have the same radix.

Section 5.6.1 is merely a list of the comparison operations. Per the list in Annex C, the compare* family of operations are not specified anywhere other than in these two sections. Rust is free to implement them as the language designers see fit, subject to the constraints above (and to good sense).