The fact that the numbers are stored in binary is significant:

In [16]: nums = [eval('1.%d5' % n) for n in range(10)]

In [17]: nums
Out[17]: [1.05, 1.15, 1.25, 1.35, 1.45, 1.55, 1.65, 1.75, 1.85, 1.95]

In [18]: [round(n, 1) for n in nums]
Out[18]: [1.1, 1.1, 1.2, 1.4, 1.4, 1.6, 1.6, 1.8, 1.9, 1.9]

Proper decimal rounding might look like:

In [20]: from decimal import Decimal

In [21]: nums = [Decimal('1.%d5' % n) for n in range(10)]

In [22]: nums
Out[22]:
[Decimal('1.05'),
 Decimal('1.15'),
 Decimal('1.25'),
 Decimal('1.35'),
 Decimal('1.45'),
 Decimal('1.55'),
 Decimal('1.65'),
 Decimal('1.75'),
 Decimal('1.85'),
 Decimal('1.95')

In [23]: [round(n, 1) for n in nums]
Out[23]:
[Decimal('1.1'),
 Decimal('1.2'),
 Decimal('1.3'),
 Decimal('1.4'),
 Decimal('1.5'),
 Decimal('1.6'),
 Decimal('1.7'),
 Decimal('1.8'),
 Decimal('1.9'),
 Decimal('2.0')]

Or with half-even rounding:

In [24]: from decimal import getcontext

In [25]: getcontext().rounding = 'ROUND_HALF_EVEN'

In [26]: [round(n, 1) for n in nums]
Out[26]:
[Decimal('1.0'),
 Decimal('1.2'),
 Decimal('1.2'),
 Decimal('1.4'),
 Decimal('1.4'),
 Decimal('1.6'),
 Decimal('1.6'),
 Decimal('1.8'),
 Decimal('1.8'),
 Decimal('2.0')]

The binary floats don't work out correct because some are above and
some are below the number suggested by the original float literal.

On Thu, 11 Apr 2019 at 02:03, Chris Smith <smi...@gmail.com> wrote:
>
> That floats are stored in binary is an implementation detail which need not 
> prevent base-10 rounding to still work. The 2nd argument to round is intended 
> to tell at which base-10 digit the rounding is to take place. By shifting 
> that digit to the ones position and then doing the rounding one can easily 
> detect whether what follows is above or below a half.
>
> >>> .345.as_integer_ratio()
> (1553741871442821, 4503599627370496)
> >>> (_*100).as_integer_ratio()
> (69, 2)
>
> "round to even" means "if what follows the digit to which you are rounding is 
> 5 then round so your digit is even". As is shown in the integer ratios above, 
> what follows the 4 is exactly 1/2 so we can round to the even 4 (as in .34) 
> instead of the odd 5 (as in .35) just like round(0.75,1) rounds to 0.8 while 
> round(0.25) rounds to 0.2.
>
> On Wednesday, April 10, 2019 at 7:29:18 PM UTC-5, Aaron Meurer wrote:
>>
>> Doesn't Python do rounding based on the binary representation of the float?
>>
>> I'm a little confused what "round to even" means in that case.
>>
>> Aaron Meurer
>>
>> On Wed, Apr 10, 2019 at 6:16 PM Chris Smith <smi...@gmail.com> wrote:
>> >
>> > Python 3 implements "round to even on tie" logic so `round(12.5)` -> 12,  
>> > not 13. I have updated, in #16608, the round function but there is a 
>> > difference in how ties are detected. I shift the desired position to the 
>> > ones position and then check for a tie so 12.345 is shifted to 1234.5 and 
>> > rounded to 1234 then is divided by 100 to give 12.34. Python doesn't do 
>> > this. I suspect it adds 0.05 and then detects that12.395 > 12395/1000 and 
>> > rounds up to 12.35
>> >
>> >
>> > >>> Rational(*.345.as_integer_ratio())-Rational(345,1000)  # .345 < 
>> > >>> 345/1000
>> > -3/112589990684262400
>> > >>> Rational(*.395.as_integer_ratio())-Rational(395,1000)  # .395 > 
>> > >>> 395/1000
>> > 1/56294995342131200
>> >
>> >
>> > >>> round(12.345,2)  # 12.345 rounds up b/c a tie is not detected
>> > 12.35
>> >
>> >
>> >
>> > Does anyone have objections to the proposed rounding?
>> >
>> > /c
>> >
>> > --
>> > You received this message because you are subscribed to the Google Groups 
>> > "sympy" group.
>> > To unsubscribe from this group and stop receiving emails from it, send an 
>> > email to sy...@googlegroups.com.
>> > To post to this group, send email to sy...@googlegroups.com.
>> > Visit this group at https://groups.google.com/group/sympy.
>> > To view this discussion on the web visit 
>> > https://groups.google.com/d/msgid/sympy/a84085c6-aa90-437c-b063-a87f909beac4%40googlegroups.com.
>> > For more options, visit https://groups.google.com/d/optout.
>
> --
> You received this message because you are subscribed to the Google Groups 
> "sympy" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to sympy+unsubscr...@googlegroups.com.
> To post to this group, send email to sympy@googlegroups.com.
> Visit this group at https://groups.google.com/group/sympy.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/sympy/7873bfe6-6f91-4d39-af6f-9f4039714fa8%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
"sympy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sympy+unsubscr...@googlegroups.com.
To post to this group, send email to sympy@googlegroups.com.
Visit this group at https://groups.google.com/group/sympy.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sympy/CAHVvXxTJQS4nC5TOL5nvAE5P2YQ97dLr%2BD3zApgrL%2BpVPoXz%3DQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to