It's down to precision.
When you use == to compare two values, they have to be exactly the same to match: so you wouldn't expect something along the lines of "hello there." to exactly match "hello there!" and when you come to numbers it's the same.
when you compile
if(2==45.000/22.5)
The compiler looks at teh code and:it to
45.000 - floating point constant value, 45.0
22.5 - floating point constant value, 22.5
So change to constant value: 45.0/22.5
if(2==2.0)
2 integer constant value: cast to floating point constant value, 2.0
if(2.0==2.0)
constant comparison: evaluate - true. Remove comparison if optimized
When you compare the next values
if(2==2.000000000001)
2.000000000001 - floating point constant value, 2.000000000001
2 - integer constant value, cast to float 2.0
if(2.0==2.000000000001)
constant comparison: evalutate - false. Remove comparison if optimized
When you try your third:
if(2==2.000000000000000000000001)
The same thing happens, but when it evaluates 2.000000000000000000000001 as a floating point number there aren't enough digits places in the binary representation of a floating point number to include the trailing "1" so it evaluates as 2.0.
A floating point number has to fit inside a 32 or 64 bit (sometimes 128 bit) binary value, and if there aren't enough bits to fit, it will be truncated.
There is a good (if technical) description on Wiki:
Single-precision_floating-point_format[
^]