5

So, according to Apple's documentation about NSRoundBankers:

Round to the closest possible return value; when halfway between two possibilities, return the possibility whose last digit is even.

While this is true for positive numbers, I am not getting the expected behaviour on negative numbers. Here is the piece of code I executed on the device and on the simulator, both printing the exact same results:

NSDecimalNumber *increment = [NSDecimalNumber decimalNumberWithMantissa:5 exponent:-2 isNegative:NO];
NSDecimalNumber *number = [NSDecimalNumber decimalNumberWithMantissa:10 exponent:-1 isNegative:YES];
NSDecimalNumberHandler *handler = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundBankers scale:1 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:YES];
while ([number compare:@1] == NSOrderedAscending)
{
    NSLog(@";%@;%@", number, [number decimalNumberByRoundingAccordingToBehavior:handler]);
    number = [number decimalNumberByAdding:increment];
}

On negative numbers, it's not returning the one whose last digit is even, it basically rounds down.

For example, for -0.85 i should be getting -0.8, but I am getting -0.9

Am I doing something wrong?

Left table shows the ACTUAL behaviour, in red marked the wrong rounded values.

Right table shows the EXPECTED behaviour, in green the correct rounded values.

iOS Java

lupidan
  • 573
  • 1
  • 7
  • 20
  • it happened only for -0.85....have you tried for other numbers too? – Teja Nandamuri Jul 28 '15 at 13:02
  • Yeah you can see in the table -0.65 should be -0.6 but it's -0.7 same thing with -0.45, -0.25, -0.05..... – lupidan Jul 28 '15 at 13:06
  • have you tried nsroundplain? If that doesn't workout too....then report it to apple!!! – Teja Nandamuri Jul 28 '15 at 13:09
  • We need to have the same behaviour on Backend and Clients, so I can't really choose a different rounding method. :/ – lupidan Jul 28 '15 at 13:33
  • In the documentation: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Protocols/NSDecimalNumberBehaviors_Protocol/#//apple_ref/c/tdef/NSRoundingMode Apple shows an example of NSRoundBankers rounding -1.35 to -1.4, so that does appear to be the designed behavior. – Brad Larson Jul 28 '15 at 14:21
  • -1.35 rounding to -1.4 makes sense (digit 4 is an even number) -1.45 rounding to -1.5 does not make sense (digit 5 is an odd number) -1.45 should be rounded to -1.4 – lupidan Jul 28 '15 at 15:23
  • I ran into the same problem using Swift and ended up here. Sadly, no one has answered this question – aeropapa17 Nov 17 '17 at 02:00
  • I did discover that the Swift class NumberFormatter DOES handle .roundHalfEven correctly. It can be used to round negative numbers correctly. Unfortunately, you have to convert the number to a String and then back to a number. Ugh. – aeropapa17 Nov 17 '17 at 02:11

1 Answers1

1

Stumbled upon this today and it's probably a bug in Foundation. If the source code of swift-corelibs-foundation has anything to do with the actual Foundation code, I might have found the culprit: https://github.com/apple/swift-corelibs-foundation/blob/70f8af962ff182c78a81673e75fe725b5b1b7827/Foundation/Decimal.swift#L1970.

I believe 1 should be subtracted from remainder on the line 1970, not added to it. Rationale: if remainder is 5, what does adding 1 to it actually change? The case falls trough (line 1972) and the check on line 1974 succeeds either way, be it 5 or 6. If it were to become 4 for after subtracting, it will prevent adding 1 to self (line 1979) and keep the number even.

UPD the issue has been reported to Apple: FB7565793.

UPD 2 the issue has been fixed by Apple in the first betas of iOS 14 / macOS 11.0.

Nikolay Kasyanov
  • 897
  • 5
  • 14