Created
January 23, 2013 11:19
-
-
Save mikecsh/4604538 to your computer and use it in GitHub Desktop.
CPDecimalCompare Problem
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* AppController.j | |
* CPDecimalTest | |
* | |
* Created by You on January 11, 2013. | |
* Copyright 2013, Your Company All rights reserved. | |
*/ | |
var debugCPDecimalCompare; | |
@import <Foundation/CPObject.j> | |
@implementation AppController : CPObject | |
{ | |
} | |
- (void)applicationDidFinishLaunching:(CPNotification)aNotification | |
{ | |
var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], | |
contentView = [theWindow contentView]; | |
var label = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; | |
[label setStringValue:@"Open the console!"]; | |
[label setFont:[CPFont boldSystemFontOfSize:24.0]]; | |
[label sizeToFit]; | |
[label setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin | CPViewMinYMargin | CPViewMaxYMargin]; | |
[label setCenter:[contentView center]]; | |
[contentView addSubview:label]; | |
[theWindow orderFront:self]; | |
debugCPDecimalCompare = NO; | |
console.log("The following tests show that [CPDecimalNumber -compare:] incorrectly evaluates numbers in the range 0 to 0.999999... as less than zero."); | |
[self isNegative:@"1"]; | |
[self isNegative:@"0.99999"]; | |
[self isNegative:@"0.25"]; | |
[self isNegative:@"0.0"]; | |
[self isNegative:@"0"]; | |
[self isNegative:@"0.25"]; | |
[self isNegative:@"2.25"]; | |
[self isNegative:@"-2.25"]; | |
console.log("\nEnabling debug flag to log CPDecimalCompare internals"); | |
debugCPDecimalCompare = YES; | |
console.log("\nThe following is WRONG"); | |
[self isNegative:@"0.25"]; | |
console.log("\nThe following is CORRECT"); | |
[self isNegative:@"1.25"]; | |
console.log("\nFor some reason the rightOperand._mantissa.length of [CPDecimalNumber zero] is different over the last two calls.."); | |
} | |
- (void)isNegative:(CPString)stringRepresentationOfNumber | |
{ | |
var decimalNumber = [CPDecimalNumber decimalNumberWithString:stringRepresentationOfNumber], | |
comparisonResult = [decimalNumber compare:[CPDecimalNumber zero]]; | |
console.log("\nEvaluating: is " + [decimalNumber stringValue] + " < 0?"); | |
if (comparisonResult === CPOrderedAscending) | |
{ | |
console.log("\tCappuccino thinks " + stringRepresentationOfNumber + " is less than zero"); | |
} | |
else if (comparisonResult === CPOrderedSame) | |
{ | |
console.log("\tCappuccino thinks " + stringRepresentationOfNumber + " is equal to zero"); | |
} | |
else if (comparisonResult === CPOrderedDescending) | |
{ | |
console.log("\tCappuccino thinks " + stringRepresentationOfNumber + " is greater thank zero"); | |
} | |
} | |
@end | |
/*! | |
* This function has been taken from CPDecimal.j and had some logging added to try and work out what's going on. | |
*/ | |
function CPDecimalCompare(leftOperand, rightOperand) | |
{ | |
if (leftOperand._isNaN && rightOperand._isNaN) | |
return CPOrderedSame; | |
if (leftOperand._isNegative != rightOperand._isNegative) | |
{ | |
if (rightOperand._isNegative) | |
return CPOrderedDescending; | |
else | |
return CPOrderedAscending; | |
} | |
// Before comparing number size check if zero (dont use CPDecimalIsZero as it is more computationally intensive) | |
var leftIsZero = (leftOperand._mantissa.length == 1 && leftOperand._mantissa[0] == 0), | |
rightIsZero = (rightOperand._mantissa.length == 1 && rightOperand._mantissa[0] == 0), | |
// Sign is the same, quick check size (length + exp) | |
s1 = leftOperand._exponent + leftOperand._mantissa.length, | |
s2 = rightOperand._exponent + rightOperand._mantissa.length; | |
/*! | |
* The problem *seems* to be that s1 < s2 for numbers >= 0 and < 1, and rightOperand._isNegative is (correctly) false | |
* This means | |
*/ | |
if (leftIsZero || s1 < s2) | |
{ | |
if (debugCPDecimalCompare) | |
{ | |
console.log("leftOperand:", CPDecimalString(leftOperand, nil)); | |
console.log("rightOperand:", CPDecimalString(rightOperand, nil)); | |
console.log("leftIsZero:", leftIsZero ? "true" : "false"); | |
console.log("rightIsZero:", rightIsZero ? "true" : "false"); | |
console.log("s1 < s2:", s1 < s2 ? "true" : "false"); | |
console.log("leftOperand._exponent:", leftOperand._exponent); | |
console.log("leftOperand._mantissa.length:", leftOperand._mantissa.length); | |
console.log("rightOperand._exponent:", rightOperand._exponent); | |
console.log("rightOperand._mantissa.length:", leftOperand._mantissa.length); | |
} | |
if (rightOperand._isNegative) | |
{ | |
if (debugCPDecimalCompare) | |
console.log("rightOperand._isNegative: true"); | |
return CPOrderedDescending; | |
} | |
else | |
{ | |
if (debugCPDecimalCompare) | |
console.log("rightOperand._isNegative: false"); | |
return CPOrderedAscending; | |
} | |
} | |
if (rightIsZero || s1 > s2) | |
{ | |
if (debugCPDecimalCompare) | |
{ | |
console.log("leftOperand:", CPDecimalString(leftOperand, nil)); | |
console.log("rightOperand:", CPDecimalString(rightOperand, nil)); | |
console.log("leftIsZero:", leftIsZero ? "true" : "false"); | |
console.log("rightIsZero:", rightIsZero ? "true" : "false"); | |
console.log("s1 < s2:", s1 < s2 ? "true" : "false"); | |
console.log("leftOperand._exponent:", leftOperand._exponent); | |
console.log("leftOperand._mantissa.length:", leftOperand._mantissa.length); | |
console.log("rightOperand._exponent:", rightOperand._exponent); | |
console.log("rightOperand._mantissa.length:", leftOperand._mantissa.length); | |
} | |
if (debugCPDecimalCompare) | |
console.log("rightIsZero"); | |
if (rightOperand._isNegative) | |
{ | |
if (debugCPDecimalCompare) | |
console.log("rightOperand._isNegative: true"); | |
return CPOrderedAscending; | |
} | |
else | |
{ | |
if (debugCPDecimalCompare) | |
console.log("rightOperand._isNegative: false"); | |
return CPOrderedDescending; | |
} | |
} | |
// Same size, so check mantissa | |
var l = MIN(leftOperand._mantissa.length, rightOperand._mantissa.length), | |
i = 0; | |
for (; i < l; i++) | |
{ | |
var d = rightOperand._mantissa[i] - leftOperand._mantissa[i]; | |
if (d > 0) | |
{ | |
if (rightOperand._isNegative) | |
return CPOrderedDescending; | |
else | |
return CPOrderedAscending; | |
} | |
if (d < 0) | |
{ | |
if (rightOperand._isNegative) | |
return CPOrderedAscending; | |
else | |
return CPOrderedDescending; | |
} | |
} | |
// Same digits, check length | |
if (leftOperand._mantissa.length > rightOperand._mantissa.length) | |
{ | |
if (rightOperand._isNegative) | |
return CPOrderedAscending; | |
else | |
return CPOrderedDescending; | |
} | |
if (leftOperand._mantissa.length < rightOperand._mantissa.length) | |
{ | |
if (rightOperand._isNegative) | |
return CPOrderedDescending; | |
else | |
return CPOrderedAscending; | |
} | |
return CPOrderedSame; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment