1

I am trying to divide 2 float numbers using integer division. I am not using numpy or any other library.

Just pure python.

6.3//2.1

#output
2.0

I tried to break my problem into fractions like:

(63/10)//(21/10)

#output
2.0

Still the same output.

I know 2.1 * 3.0 == 6.3

So, I am expecting 3.0 as output.

Please can someone explain?

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Talha Tayyab
  • 8,111
  • 25
  • 27
  • 44
  • 1
    Why are you using `//` with non-integers? – Scott Hunter Jul 26 '23 at 17:32
  • `63/10` is a poor approximation of the value the floating-point literal `6.3` actually represents (and the same for `21/10` and `2.1`). You can use `Decimal.as_integer_ratio` to get more accurate approximations for the `float` values *actually* produced by the two `float` literals. – chepner Jul 26 '23 at 17:39
  • 3
    I don't believe this is a floating point rounding error. `6.3/2.1` will give `3.0`. I think this question should be re-opened rather than closed as a duplicate. – Michael Cao Jul 26 '23 at 17:40
  • 1
    @chepner `63/10 == 6.3` is of course true, so I wouldn't call that a "poor approximation". – Kelly Bundy Jul 26 '23 at 17:43
  • Please forgive me, somehow I am not satisfied by the duplicate answers. Maybe I am missing something? – Talha Tayyab Jul 26 '23 at 17:45
  • 2
    @OneCricketeer *"If the result is 2.99999"* In this case it doesn't seem to be. `math.floor(6.3 / 2.1)` gives 3 rather than 2. – slothrop Jul 26 '23 at 17:45
  • @KellyBundy That's because `63/10` produces a similar approximation. I'm talking about the difference between the rational number "sixty-three tenths" and the dyadic rational that the literal `6.3` represents. – chepner Jul 26 '23 at 17:46
  • You can also compare `Decimal('6.3') // Decimal('2.1')` (which uses exact representations of the intended rational numbers) to `Decimal(6.3) // Decimal(2.1)` (which does not and produces the same result of `2`. – chepner Jul 26 '23 at 17:49
  • @chepner I suggest you don't use code markdown then, i.e., write 63/10 instead of `63/10`. – Kelly Bundy Jul 26 '23 at 17:49
  • 3
    @chepner it's true that `6.3` isn't the same as the rational 63/10. But that doesn't itself explain a discrepancy between `math.floor(6.3 / 2.1)` (gives 3), and `6.3 // 2.1`, which according to PEP238 means `floor(6.3 / 2.1)` and yet gives 2. https://peps.python.org/pep-0238/#semantics-of-floor-division – slothrop Jul 26 '23 at 17:53
  • 3
    @TalhaTayyab As the top duplicate answer explains, for example `0.1` isn't 0.1 but a bit larger. Similarly, your `6.3` is a bit smaller than 6.3 and your `2.1` is a bit larger than 2.1, so the fraction is a bit smaller than 3, and thus gets floored to 2. – Kelly Bundy Jul 26 '23 at 17:54
  • @KellyBundy thanks.. I appreciate it. – Talha Tayyab Jul 26 '23 at 18:00
  • For a better visual - `print('{:9f}'.format(Decimal(6.3)/Decimal(2.1)))` - `2.999999999999999788528947690` – OneCricketeer Jul 26 '23 at 18:01
  • 2
    @KellyBundy so what's going on here is that the \\ operation for floats has enough 'intermediate precision' to know that `6.3 / 2.1` is smaller than 3, even though the nearest valid float to the result of the division is exactly 3? So that would explain why `6.3 / 2.1 == 3` and `math.floor(6.3/2.1) == 3` and yet `6.3 // 2.1 == 2`. – slothrop Jul 26 '23 at 18:01
  • 2
    @slothrop Looks like the PEP is wrong there. The [doc](https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations) gets it right: *"the result is that of **mathematical** division with the ‘floor’ function applied to the result"*. – Kelly Bundy Jul 26 '23 at 18:01
  • 1
    @slothrop Yes, enough 'intermediate precision' to reflect the mathematically exact result floored. In general, think of taking the exact represented operand values (slightly smaller than 6.3 and slightly larger than 2.1 here), calculating the exact mathematical result (and for `//` floor it), and only then producing the closest `float` value of the mathematical result. – Kelly Bundy Jul 26 '23 at 18:10
  • I found in the doc that `x//y` returns the smaller of `math.floor(6.3/2.1)` or `(x-x%y)//y` as it has to keep `divmod(x,y)[0] * y + x % y` be very close to `x` – Talha Tayyab Jul 26 '23 at 18:13

0 Answers0