Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python Python Basics (2015) Python Data Types Numbers

James N
James N
17,864 Points

int(5.999999999999999) i got 6? i don't get it.

according to kenneth, when you use the int() method on a float, it returns the whole number of the float, and just chops of the decimal. however, when i tried to run int(5.9999999999999999999999), I expected the function to return 5. not 6. is this just one of the "weird" things with floats? or is this something more? I don't understand what's going on here. Can someone explain it for me? Thanks!

4 Answers

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 68,454 Points

Now I'm REALLY curious. Having the 16th 9 seems to make the difference. It's not the int operation causing the change. It is a limitation of the floating point representation. A longer read on these limits in Python and all computer languages see Floating Point Arithmetic: Issues and Limitations

As for your case, Let's dig in...

$ python3
Python 3.4.3 (default, Oct 14 2015, 20:28:29) 
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 5.999999999999999  # 15 9's
5.999999999999999
>>> 5.9999999999999999  # 16 9's
6.0

# Starting with binary notation
# 5 in binary is
>>> bin(5)
'0b101'
# that's 1 * 2**2 + 0 * 2**1 + 1 * 2**0  =  4 + 0 + 1 = 5

# Now let's look at float representation. 

# Floats are stored as 53 bits (or a 1 followed by 13 hexadecimal characters)
# Hexadecimal characters represent 4-bits, have 16 possible values:0-9a-f
>>> float.hex(5.0)
'0x1.4000000000000p+2'

# converting that to the full 53-bit version would be
# 0b1.0100000000000000000000000000000000000000000000000000p+2 binary
# the 'p+2 means it's shifted by two bit, so
# 0b1.01000000...p+2 == 0b101.000000...p+0
# Now the 5 in binary is clearly seen
# Back to float representation of 5 in hex
>>> float.hex(5.0)
'0x1.4000000000000p+2'

# as you increase the value, the HEX value increases
>>> float.hex(5.1)
'0x1.4666666666666p+2'
>>> float.hex(5.2)
'0x1.4cccccccccccdp+2'
>>> float.hex(5.3)
'0x1.5333333333333p+2'
>>> float.hex(5.4)
'0x1.599999999999ap+2'
>>> float.hex(5.5)
'0x1.6000000000000p+2'
>>> float.hex(5.6)
'0x1.6666666666666p+2'
>>> float.hex(5.7)
'0x1.6cccccccccccdp+2'
>>> float.hex(5.8)
'0x1.7333333333333p+2'
>>> float.hex(5.9)
'0x1.799999999999ap+2'

# As you add more 9's it will approach 0x1.8000...p+2 which is 6:
>>> float.hex(5.99)
'0x1.7f5c28f5c28f6p+2'
>>> float.hex(5.9999)
'0x1.7ffe5c91d14e4p+2'
>>> float.hex(5.99999999)
'0x1.7ffffff543389p+2'
>>> float.hex(5.999999999999)
'0x1.7fffffffffb9ap+2'
>>> float.hex(5.999999999999999)  # 15 9's
'0x1.7ffffffffffffp+2'

# in binary that's
'0b1.111111111111111111111111111111111111111111111111111p+2
# this is the highest number before it rolls over
>>> float.hex(5.9999999999999999)  # 16 9's
'0x1.8000000000000p+2'
>>> float.hex(6.0)
'0x1.8000000000000p+2' = 

# in binary this is:
'0b1.1000...p+2' = '0b110.00...p+0'

# 6  in binary is
>>> bin(6)
'0b110'

As the integer portion of a number increases, fewer of the 53 bits remain for the fractional part. This means that fewer 9's are needed to round up to the next integer:

>>> float.hex(1024.0) 
'0x1.0000000000000p+10'
>>> float.hex(1024.9)
'0x1.003999999999ap+10'
>>> float.hex(1024.999999999)  # nine 9's
'0x1.003ffffffeed2p+10'
>>> float.hex(1024.999999999999)  # 12 9's
'0x1.003fffffffffcp+10'
>>> float.hex(1024.9999999999999)  # 13 9's
'0x1.0040000000000p+10'
>>> float.hex(1025.0)
'0x1.0040000000000p+10'

# starting with 2**40 = 1099511627776
>>> float.hex(1099511627776.0)
'0x1.0000000000000p+40'
>>> float.hex(1099511627776.9)
'0x1.0000000000e66p+40'
>>> float.hex(1099511627776.99)
'0x1.0000000000fd7p+40'
>>> float.hex(1099511627776.999)
'0x1.0000000000ffcp+40'
>>> float.hex(1099511627776.9999)  # four 9's
'0x1.0000000001000p+40'
>>> float.hex(1099511627777.0)
'0x1.0000000001000p+40'

# Getting 2**50, very little precision remains:
>>> 1125899906842624.4 == 1125899906842624.5 == 1125899906842624.6
True
>>> 1125899906842624.9 == 1125899906842625.0
True

>>> float.hex(1125899906842624.4)
'0x1.0000000000002p+50'
>>> float.hex(1125899906842624.5)
'0x1.0000000000002p+50'
>>> float.hex(1125899906842624.6)
'0x1.0000000000002p+50'
>>> float.hex(1125899906842624.7)
'0x1.0000000000003p+50'
>>> float.hex(1125899906842624.8)
'0x1.0000000000003p+50'
>>> float.hex(1125899906842624.9)
'0x1.0000000000004p+50'
>>> float.hex(1125899906842625.0)
'0x1.0000000000004p+50'

As a final curiosity with binary numbers, when you multiply a number by 2, it's binary representation is simply shift by one bit position:

>>> float.hex(5.0)
'0x1.4000000000000p+2'
>>> float.hex(10.0)
'0x1.4000000000000p+3'
>>> float.hex(20.0)
'0x1.4000000000000p+4'
>>> float.hex(40.0)
'0x1.4000000000000p+5'

Notice how the signifcand value stays the same, just the shifted "power" number increase by 1

Nathan Tallack
Nathan Tallack
22,160 Points

In the immortal words of Keanu... Woah.

James N
James N
17,864 Points

I Noticed that you used 2 asterisks for the 2**2 portion of the comment. Just curious, is that an exponent sign? and if so, will it work in other languages?

# Starting with binary notation
# 5 in binary is
>>> bin(5)
'0b101'
# that's 1 * 2**2 + 0 * 2**1 + 1 * 2**0  =  4 + 0 + 1 = 5
Chris Freeman
Chris Freeman
Treehouse Moderator 68,454 Points

Yes, In Python and Perl and other languages, two asterisks (**) means "raised to the power". In some Math book notations a caret (^) is used, but this means bit-wise exclusive OR, in Python and Perl.

still no idea... can someone make it simple can easy to understand...

Chris Freeman
Chris Freeman
Treehouse Moderator 68,454 Points

Your comment... Sky Lu, to be manipulated by computers, all numbers must be stored in the native binary format of computers. In the case of integers, each binary bit represents the values 1, 2, 4, 8, 16, 32, 64, 128, 256, and so on. Adding up each position to get the total value. 11 would be stored as b1011 which is 4 + 2 + 1.

Fractions work in a similar manner except each bit represents a fractional portion of the value. Each bit represents 1/2, 1/4, 1/8, 1/16, 1/32, 1/64, 1/128, 1/256, and so on of the base value.

As mentioned in my answer above, 5 is represented as:

1.4000000000000p+2 #hex

1.0100000000000000000000000000000000000000000000000000p+2 # binary

The "1." at the beginning and the "p+2" represent 1 times 2^2 (2 to the power 2). This is 4. The first 4 bits after the point ".0100" represent a fractional value of this starting value 4:

0*4*1/2 + 1*4*1/4 + 0*4*1/8 + 0*4*1/16 + ...

0*2 + 1*1 + 0*1/2 + 0*1/4 + ...

0 + 1 + 0 + 0

1

This 1, plus the starting 4, gives the desired value 5.

The limitation of using a 53-bit floating point representation is the precision granularity depends on the size of the smallest fractional bit.

# the smallest fractional represented by the 52nd binary bit has avalue of

1/(2^52)
1/4,503,599,627,370,496
2.22e-16
0.000000000000000222

There are not enough bits to differentiate numbers with a difference smaller than this smallest fraction.

As a last example, the number 5.0000000000000001 can not be differentiated from 5 because the last fractional bit is not small enough to represent the fractional part "0.0000000000000001"

>>> 5.0000000000000001 == 5
True

Hope this helps.

Hi Chris, thank you very much for your detail reply. I just don't understand, why 5 is represented as 1.4000000000000p+2 #hex, DEC5 to HEX should be 5 again, right? DEC5 to binary should be 101 as I understand. How DEC5 shows 1.0100000000000000000000000000000000000000000000000000p+2 # binary

Chris Freeman
Chris Freeman
Treehouse Moderator 68,454 Points

Hi Sky, The difference is whether the object is an int or a float. As an int, "5" in

# store 5 as in int
>>> fiveint = 5
>>> fiveint
5
# show hex representation of int 5
>>> hex(fiveint)
'0x5'
# show binary representation of int 5 
>>> bin(fiveint)
'0b101'

Note the hex() function only works on integers and does not work on floats. To get the hex representation of a float use the method float.hex().

A float object is stored differently than an int object. The leading number on a float is always 1 unless the value is exactly Zero. The exponent "power" suffix indicates how much the point between the integer portion and the fraction portion is shifted in interpreting the value. The value 5 as a float and an int are related. Below I show how the float representation can be interpreted to see the binary value of the integer.

# storing 5 as a float
>>> fivefloat = 5.0
>>> fivefloat
5.0
# show hex representation of float 5
>>> fivefloat.hex()
'0x1.4000000000000p+2'

# the p+2 is a binary power of two or 2*2 = 4
# It can also be used to shift the value left for each positive power
# these values are the same
'0x1.4000000000000p+2'
'0x2.8000000000000p+1'
'0x5.0000000000000p+0'

# in pseudo-binary it would look like something like
'b1.0100 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000p+2'
'b10.100 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000p+1'
'b101.00 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000p+0'

# Notice the last term. "p+0" is zero, so this is the same as
'b101'
Nathan Tallack
Nathan Tallack
22,160 Points

That is strange. When I open a Python workspace here on TeamTreehouse I get 5 from that. Consider the output below.

treehouse:~/workspace$ python                                                                      
Python 3.5.0 (default, Dec  8 2015, 20:56:53)                                                      
[GCC 4.8.3 20140911 (Red Hat 4.8.3-9)] on linux                                                    
Type "help", "copyright", "credits" or "license" for more information.                             
>>> int(5.999999999999999)                                                                         
5                                                                                                  
>>>                                                                                                

Where are you getting your results from?

James N
James N
17,864 Points

Workspaces, just like you.

Here's the output:

Python 3.5.0 (default, Dec  8 2015, 20:
56:53)                                 
[GCC 4.8.3 20140911 (Red Hat 4.8.3-9)] 
on linux                               
Type "help", "copyright", "credits" or 
"license" for more information.        
>>> int(5.999999999999999999)          
6   
Nathan Tallack
Nathan Tallack
22,160 Points

More 9's in yours that time. It seems that once you get to 16 decimal places it rounds up. I suspect this has to do with the INT type we are using where we are wrapping around a binary counter someplace.

Any guru's out there want to edumacate us? ;)

James N
James N
17,864 Points

Wow. I Started a popular thread. LOL

@Chris great explanations thanks I was curious the underlying reasoning behind why it behaves that way and explaining how binary bits work with numbers was extremely helpful.