0

I would like to turn float integers (123.0) into ints (123).

What I would like the function to do:

Input: 2.1 Output: Exception, cannot turn float into int

Input: 2.0 Output: 2

Using int() on a float seems to just be math.floor() and that is not what I'm looking for.

bachzealot
  • 11
  • 2

3 Answers3

3

You can check if after you use int() it the same value as the float

def convert(num):
    if num == int(num):
        return int(num)
    raise Exception('Cannot turn float into int')

As a side note, using int() is not exactly as using math.floor(), try with negative numbers. What is the difference between int() and floor() in Python 3?

Guy
  • 46,488
  • 10
  • 44
  • 88
3

I don't know of a built-in that does it directly, but it is easy to create your own function. You can use .is_integer() on the input-value to check if the float is directly castable to int:

def strict_int(value):
    if value.is_integer():
        return int(value)
    raise ValueError("cannot turn uneven float into int")


print(strict_int(3.0))
print(strict_int(3.1))

Output:

3
...
ValueError: cannot turn uneven float into int

But be warned, that there may be some unexpected behavior resulting from the way floats are represented. Try this for example:

print(strict_int(0.3 + 0.3 + 0.3 + 0.1))

This "1.0" will fail when trying to strictly convert to an int as it is in fact 0.9999999999999999! If you use the standard int it will work in that it gives you a result, but the result for int(0.3 + 0.3 + 0.3 + 0.1) is 0, probably not what you'd expect. But this is a general issue with how floats are represented and not directly related to the used methods. So you'll encounter this anywhere floats are present.

Here is an interesting post that goes a bit more into detail about the potential issues.

MangoNrFive
  • 1,541
  • 1
  • 10
  • 23
2

I guess i would just do

def convert(n):
    return int(f"{n:g}")
Joran Beasley
  • 110,522
  • 12
  • 160
  • 179
  • This is simple and does the work but without custom `exception`. However, this could be confusing to python-newbies. Could you please at least clarify how does it work? – JohnyCapo Nov 21 '22 at 10:46
  • EDIT: Well I know that int(float.number) would cause `Exception` but I thought that there is a **trick** in `:g`.. Well there is not. Is there a reason for that `:g` to be there? – JohnyCapo Nov 21 '22 at 10:51
  • Elegant and short, I like it! Even though as JohnyCapo pointed out not as easy to understand what's going on at first. The `:g` is necessary, otherwise it will fail on an even float as well. It has to do with the [Number formatting for f-strings](https://cheatography.com/brianallan/cheat-sheets/python-f-strings-number-formatting/). `:g` defines it using the general format which basically cuts of trailing zeros as I understand it. – MangoNrFive Nov 21 '22 at 11:20
  • Why this works then, is that floats and strings are treated differently when converting to int. The float has digits cut off to an integer. The string is only converted when it already is a valid int. Even `int("1.0")` doesn't work, and that's what the `:g` is for, it makes a `1` out of the `1.0` that then can be converted from the string to an int. – MangoNrFive Nov 21 '22 at 11:24
  • This fails on floats larger than one million: `convert(1000000.0)` gives a `ValueError` where presumably it's expected to return the integer `1000000` instead. It also fails in the other direction for (for example) `2.000001`, which returns `2` instead of raising. (Similarly for `123456.5`) – Mark Dickinson Nov 21 '22 at 15:26
  • 1
    The reason why it fails is, that for numbers this big the general format uses the scientific notation which is then not a valid int-string. Try that with `print(f"{1000000.0:g}")` -> `1e+06`. You can force a higher precision, then it uses the scientific notation later like: `print(f"{1000000.0:.16g}")`. The precision of 16 is just an example, probably makes sense to set it to the precision of floats, whatever that is. Or you can use a big value that is enough in any case like `print(f"{1000000.0:.1000g}")`. – MangoNrFive Nov 21 '22 at 15:56