mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-11-14 10:43:50 +00:00
Merge branch 'CPDecimalNumber'
This commit is contained in:
commit
b7d7b99a82
6 files changed
+3559
No files matched your search
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,702 @@
|
||||
/*
|
||||
* CPDecimalNumber.j
|
||||
* Foundation
|
||||
*
|
||||
* Created by Stephen Paul Ierodiaconou
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPObject.j"
|
||||
@import "CPDecimal.j"
|
||||
@import "CPException.j"
|
||||
|
||||
/* The protocol is defined as : Make sure CPDecimalNumberHandler implements these methods
|
||||
@protocol CPDecimalNumberBehaviors
|
||||
- (CPRoundingMode)roundingMode;
|
||||
- (short)scale;
|
||||
- (CPDecimalNumber)exceptionDuringOperation:(SEL)operation error:(CPCalculationError)error leftOperand:(CPDecimalNumber)leftOperand rightOperand:(CPDecimalNumber)rightOperand;
|
||||
@end
|
||||
*/
|
||||
|
||||
/*! @class CPDecimalNumberHandler
|
||||
@ingroup foundation
|
||||
@brief Decimal floating point number exception and rounding behavior. This
|
||||
class is mutable.
|
||||
*/
|
||||
// protocols this implements <CPCoding, CPDecimalNumberBehaviors>
|
||||
@implementation CPDecimalNumberHandler : CPObject
|
||||
{
|
||||
CPRoundingMode _roundingMode;
|
||||
short _scale;
|
||||
BOOL _raiseOnExactness;
|
||||
BOOL _raiseOnOverflow;
|
||||
BOOL _raiseOnUnderflow;
|
||||
BOOL _raiseOnDivideByZero;
|
||||
}
|
||||
|
||||
// initializers
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithRoundingMode:(CPRoundingMode)roundingMode scale:(short)scale raiseOnExactness:(BOOL)exact raiseOnOverflow:(BOOL)overflow raiseOnUnderflow:(BOOL)underflow raiseOnDivideByZero:(BOOL)divideByZero
|
||||
{
|
||||
if (self = [self init])
|
||||
{
|
||||
_roundingMode = roundingMode;
|
||||
_scale = scale;
|
||||
_raiseOnExactness = exact;
|
||||
_raiseOnOverflow = overflow;
|
||||
_raiseOnUnderflow = underflow;
|
||||
_raiseOnDivideByZero = divideByZero;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// class methods
|
||||
+ (id)decimalNumberHandlerWithRoundingMode:(CPRoundingMode)roundingMode scale:(short)scale raiseOnExactness:(BOOL)exact raiseOnOverflow:(BOOL)overflow raiseOnUnderflow:(BOOL)underflow raiseOnDivideByZero:(BOOL)divideByZero
|
||||
{
|
||||
return [[self alloc] initWithRoundingMode:roundingMode scale:scale raiseOnExactness:exact raiseOnOverflow:overflow raiseOnUnderflow:underflow raiseOnDivideByZero:divideByZero];
|
||||
}
|
||||
|
||||
+ (id)defaultDecimalNumberHandler
|
||||
{
|
||||
return _cappdefaultDcmHandler;
|
||||
}
|
||||
|
||||
// CPCoding methods
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aDecoder
|
||||
{
|
||||
}
|
||||
|
||||
// CPDecimalNumberBehaviors methods
|
||||
- (CPRoundingMode)roundingMode
|
||||
{
|
||||
return _roundingMode;
|
||||
}
|
||||
|
||||
- (short)scale
|
||||
{
|
||||
return _scale;
|
||||
}
|
||||
|
||||
// FIXME: LOCALE?
|
||||
- (CPDecimalNumber)exceptionDuringOperation:(SEL)operation error:(CPCalculationError)error leftOperand:(CPDecimalNumber)leftOperand rightOperand:(CPDecimalNumber)rightOperand
|
||||
{
|
||||
// default behavior of throwing exceptions a la gnustep
|
||||
switch (error)
|
||||
{
|
||||
case CPCalculationNoError:
|
||||
return nil;
|
||||
case CPCalculationOverflow:
|
||||
if (_raiseOnOverflow)
|
||||
[CPException raise:CPDecimalNumberOverflowException reason:("A CPDecimalNumber overflow has occured. (Left operand= '" + [leftOperand descriptionWithLocale:nil] + "' Right operand= '" + [rightOperand descriptionWithLocale:nil] + "' Selector= '" + operation + "')") ];
|
||||
else
|
||||
return [CPDecimalNumber maximumDecimalNumber]; // there was overflow return largest possible val
|
||||
break;
|
||||
case CPCalculationUnderflow:
|
||||
if (_raiseOnUnderflow)
|
||||
[CPException raise:CPDecimalNumberUnderflowException reason:("A CPDecimalNumber underflow has occured. (Left operand= '" + [leftOperand descriptionWithLocale:nil] + "' Right operand= '" + [rightOperand descriptionWithLocale:nil] + "' Selector= '" + operation + "')") ];
|
||||
else
|
||||
return [CPDecimalNumber minimumDecimalNumber]; // there was underflow, return smallest possible value
|
||||
break;
|
||||
case CPCalculationLossOfPrecision:
|
||||
if (_raiseOnExactness)
|
||||
[CPException raise:CPDecimalNumberExactnessException reason:("A CPDecimalNumber has been rounded off during a calculation. (Left operand= '" + [leftOperand descriptionWithLocale:nil] + "' Right operand= '" + [rightOperand descriptionWithLocale:nil] + "' Selector= '" + operation + "')") ];
|
||||
else
|
||||
return nil; // Ignore.
|
||||
break;
|
||||
case CPCalculationDivideByZero:
|
||||
if (_raiseOnDivideByZero)
|
||||
[CPException raise:CPDecimalNumberDivideByZeroException reason:("A CPDecimalNumber divide by zero has occured. (Left operand= '" + [leftOperand descriptionWithLocale:nil] + "' Right operand= '" + [rightOperand descriptionWithLocale:nil] + "' Selector= '" + operation + "')") ];
|
||||
else
|
||||
return [CPDecimalNumber notANumber]; // Div by zero returns NaN
|
||||
break;
|
||||
default:
|
||||
[CPException raise:CPInvalidArgumentException reason:("An unknown CPDecimalNumber error has occured. (Left operand= '" + [leftOperand descriptionWithLocale:nil] + "' Right operand= '" + [rightOperand descriptionWithLocale:nil] + "' Selector= '" + operation + "')") ];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// create the default global behavior class
|
||||
_cappdefaultDcmHandler = [CPDecimalNumberHandler decimalNumberHandlerWithRoundingMode:CPRoundPlain scale:0 raiseOnExactness:NO raiseOnOverflow:YES raiseOnUnderflow:YES raiseOnDivideByZero:YES];
|
||||
|
||||
// After discussing with boucher about this it makes sense not to inherit, as
|
||||
// CPNumber is toll free bridged and anyway its methods will need to be
|
||||
// overrided here as CPDecimalNumber is not interchangable with CPNumbers.
|
||||
|
||||
/*! @class CPDecimalNumber
|
||||
@ingroup foundation
|
||||
@brief Decimal floating point number
|
||||
|
||||
This class represents a decimal floating point number and the relavent
|
||||
mathematical operations to go with it.
|
||||
This class is mutable.
|
||||
*/
|
||||
|
||||
|
||||
@implementation CPDecimalNumber : CPNumber
|
||||
{
|
||||
CPDecimal _data;
|
||||
}
|
||||
|
||||
+ (id)alloc
|
||||
{
|
||||
return class_createInstance(self);
|
||||
}
|
||||
|
||||
// initializers
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init])
|
||||
{}
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Initialise a CPDecimalNumber object with the contents of a CPDecimal object
|
||||
@param dcm the CPDecimal object to copy
|
||||
@return the reference to the receiver CPDecimalNumber
|
||||
*/
|
||||
- (id)initWithDecimal:(CPDecimal)dcm
|
||||
{
|
||||
if (self = [self init])
|
||||
_data = CPDecimalCopy(dcm);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// NOTE: long long doesnt exist in JS, so this is actually a double
|
||||
- (id)initWithMantissa:(unsigned long long)mantissa exponent:(short)exponent isNegative:(BOOL)flag
|
||||
{
|
||||
if (self = [self init])
|
||||
{
|
||||
if( flag )
|
||||
mantissa *= -1;
|
||||
|
||||
_data = CPDecimalMakeWithParts(mantissa, exponent);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithString:(CPString)numberValue
|
||||
{
|
||||
if (self = [self init])
|
||||
{
|
||||
_data = CPDecimalMakeWithString(numberValue, nil);
|
||||
if (_data === nil)
|
||||
[CPException raise:CPInvalidArgumentException reason:"A CPDecimalNumber has been passed an invalid string. '" + numberValue + "'"];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithString:(CPString)numberValue locale:(CPDictionary)locale
|
||||
{
|
||||
if (self = [self init])
|
||||
{
|
||||
_data = CPDecimalMakeWithString(numberValue,locale);
|
||||
if (!_data)
|
||||
[CPException raise:CPInvalidArgumentException reason:"A CPDecimalNumber has been passed an invalid string. '" + numberValue + "'"];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// class methods
|
||||
+ (CPDecimalNumber)decimalNumberWithDecimal:(CPDecimal)dcm
|
||||
{
|
||||
return [[self alloc] initWithDecimal:dcm];
|
||||
}
|
||||
|
||||
+ (CPDecimalNumber)decimalNumberWithMantissa:(unsigned long long)mantissa exponent:(short)exponent isNegative:(BOOL)flag
|
||||
{
|
||||
return [[self alloc] initWithMantissa:mantissa exponent:exponent isNegative:flag];
|
||||
}
|
||||
|
||||
+ (CPDecimalNumber)decimalNumberWithString:(CPString)numberValue
|
||||
{
|
||||
return [[self alloc] initWithString:numberValue];
|
||||
}
|
||||
|
||||
+ (CPDecimalNumber)decimalNumberWithString:(CPString)numberValue locale:(CPDictionary)locale
|
||||
{
|
||||
return [[self alloc] initWithString:numberValue locale:locale];
|
||||
}
|
||||
|
||||
+ (id)defaultBehavior
|
||||
{
|
||||
return _cappdefaultDcmHandler;
|
||||
}
|
||||
|
||||
+ (CPDecimalNumber)maximumDecimalNumber
|
||||
{
|
||||
var s = @"",
|
||||
i = 0;
|
||||
for(;i < CPDecimalMaxDigits; i++)
|
||||
s += "9";
|
||||
s += "e" + CPDecimalMaxExponent;
|
||||
return [[self alloc] initWithString:s];
|
||||
}
|
||||
|
||||
+ (CPDecimalNumber)minimumDecimalNumber
|
||||
{
|
||||
var s = @"-",
|
||||
i = 0;
|
||||
for(;i < CPDecimalMaxDigits; i++)
|
||||
s += "9";
|
||||
s += "e" + CPDecimalMinExponent;
|
||||
return [[self alloc] initWithString:s];
|
||||
}
|
||||
|
||||
+ (CPDecimalNumber)notANumber
|
||||
{
|
||||
return [[self alloc] initWithDecimal:CPDecimalMakeNaN()];
|
||||
}
|
||||
|
||||
+ (CPDecimalNumber)one
|
||||
{
|
||||
return [[self alloc] initWithString:"1"];
|
||||
}
|
||||
|
||||
+ (void)setDefaultBehavior:(id <CPDecimalNumberBehaviors>)behavior
|
||||
{
|
||||
_cappdefaultDcmHandler = behavior;
|
||||
}
|
||||
|
||||
+ (CPDecimalNumber)zero
|
||||
{
|
||||
return [[self alloc] initWithString:"0"];
|
||||
}
|
||||
|
||||
// instance methods
|
||||
- (CPDecimalNumber)decimalNumberByAdding:(CPDecimalNumber)decimalNumber
|
||||
{
|
||||
return [self decimalNumberByAdding:decimalNumber withBehavior:_cappdefaultDcmHandler];
|
||||
}
|
||||
|
||||
- (CPDecimalNumber)decimalNumberByAdding:(CPDecimalNumber)decimalNumber withBehavior:(id <CPDecimalNumberBehaviors>)behavior
|
||||
{
|
||||
// FIXME: Surely this can take CPNumber (any JS number) as an argument as CPNumber is CPDecimalNumbers super normally (not here tho)
|
||||
var result = CPDecimalMakeZero(),
|
||||
res = 0,
|
||||
error = CPDecimalAdd(result, [self decimalValue], [decimalNumber decimalValue], [behavior roundingMode]);
|
||||
|
||||
if (error > CPCalculationNoError)
|
||||
{
|
||||
res = [behavior exceptionDuringOperation:_cmd error:error leftOperand:self rightOperand:decimalNumber];
|
||||
// Gnustep does this, not sure if it is correct behavior
|
||||
if (res != nil)
|
||||
return res; // say on overflow and no exception handling, returns max decimal val
|
||||
}
|
||||
return [CPDecimalNumber decimalNumberWithDecimal:result];
|
||||
}
|
||||
|
||||
- (CPDecimalNumber)decimalNumberBySubtracting:(CPDecimalNumber)decimalNumber
|
||||
{
|
||||
return [self decimalNumberBySubtracting:decimalNumber withBehavior:_cappdefaultDcmHandler];
|
||||
}
|
||||
|
||||
- (CPDecimalNumber)decimalNumberBySubtracting:(CPDecimalNumber)decimalNumber withBehavior:(id <CPDecimalNumberBehaviors>)behavior
|
||||
{
|
||||
var result = CPDecimalMakeZero(),
|
||||
error = CPDecimalSubtract(result, [self decimalValue], [decimalNumber decimalValue], [behavior roundingMode]);
|
||||
|
||||
if (error > CPCalculationNoError)
|
||||
{
|
||||
var res = [behavior exceptionDuringOperation:_cmd error:error leftOperand:self rightOperand:decimalNumber];
|
||||
// Gnustep does this, not sure if it is correct behavior
|
||||
if (res != nil)
|
||||
return res; // say on overflow and no exception handling, returns max decimal val
|
||||
}
|
||||
return [CPDecimalNumber decimalNumberWithDecimal:result];
|
||||
}
|
||||
|
||||
- (CPDecimalNumber)decimalNumberByDividingBy:(CPDecimalNumber)decimalNumber
|
||||
{
|
||||
return [self decimalNumberByDividingBy:decimalNumber withBehavior:_cappdefaultDcmHandler];
|
||||
}
|
||||
|
||||
- (CPDecimalNumber)decimalNumberByDividingBy:(CPDecimalNumber)decimalNumber withBehavior:(id <CPDecimalNumberBehaviors>)behavior
|
||||
{
|
||||
var result = CPDecimalMakeZero(),
|
||||
error = CPDecimalDivide(result, [self decimalValue], [decimalNumber decimalValue], [behavior roundingMode]);
|
||||
|
||||
if (error > CPCalculationNoError)
|
||||
{
|
||||
var res = [behavior exceptionDuringOperation:_cmd error:error leftOperand:self rightOperand:decimalNumber];
|
||||
// Gnustep does this, not sure if it is correct behavior
|
||||
if (res != nil)
|
||||
return res; // say on overflow and no exception handling, returns max decimal val
|
||||
}
|
||||
return [CPDecimalNumber decimalNumberWithDecimal:result];
|
||||
}
|
||||
|
||||
- (CPDecimalNumber)decimalNumberByMultiplyingBy:(CPDecimalNumber)decimalNumber
|
||||
{
|
||||
return [self decimalNumberByMultiplyingBy:decimalNumber withBehavior:_cappdefaultDcmHandler];
|
||||
}
|
||||
|
||||
- (CPDecimalNumber)decimalNumberByMultiplyingBy:(CPDecimalNumber)decimalNumber withBehavior:(id <CPDecimalNumberBehaviors>)behavior
|
||||
{
|
||||
var result = CPDecimalMakeZero(),
|
||||
error = CPDecimalMultiply(result, [self decimalValue], [decimalNumber decimalValue], [behavior roundingMode]);
|
||||
|
||||
if (error > CPCalculationNoError)
|
||||
{
|
||||
var res = [behavior exceptionDuringOperation:_cmd error:error leftOperand:self rightOperand:decimalNumber];
|
||||
// Gnustep does this, not sure if it is correct behavior
|
||||
if (res != nil)
|
||||
return res; // say on overflow and no exception handling, returns max decimal val
|
||||
}
|
||||
return [CPDecimalNumber decimalNumberWithDecimal:result];
|
||||
}
|
||||
|
||||
- (CPDecimalNumber)decimalNumberByMultiplyingByPowerOf10:(short)power
|
||||
{
|
||||
return [self decimalNumberByMultiplyingByPowerOf10:power withBehavior:_cappdefaultDcmHandler];
|
||||
}
|
||||
|
||||
- (CPDecimalNumber)decimalNumberByMultiplyingByPowerOf10:(short)power withBehavior:(id <CPDecimalNumberBehaviors>)behavior
|
||||
{
|
||||
var result = CPDecimalMakeZero(),
|
||||
error = CPDecimalMultiplyByPowerOf10(result, [self decimalValue], power, [behavior roundingMode]);
|
||||
|
||||
if (error > CPCalculationNoError)
|
||||
{
|
||||
var res = [behavior exceptionDuringOperation:_cmd error:error leftOperand:self rightOperand:[CPDecimalNumber decimalNumberWithString:power.toString()]];
|
||||
// Gnustep does this, not sure if it is correct behavior
|
||||
if (res != nil)
|
||||
return res; // say on overflow and no exception handling, returns max decimal val
|
||||
}
|
||||
return [CPDecimalNumber decimalNumberWithDecimal:result];
|
||||
}
|
||||
|
||||
- (CPDecimalNumber)decimalNumberByRaisingToPower:(unsigned)power
|
||||
{
|
||||
return [self decimalNumberByRaisingToPower:power withBehavior:_cappdefaultDcmHandler];
|
||||
}
|
||||
|
||||
- (CPDecimalNumber)decimalNumberByRaisingToPower:(unsigned)power withBehavior:(id <CPDecimalNumberBehaviors>)behavior
|
||||
{
|
||||
if (power < 0)
|
||||
return [behavior exceptionDuringOperation:_cmd error:-1 leftOperand:self rightOperand:[CPDecimalNumber decimalNumberWithString:power.toString()]];
|
||||
|
||||
var result = CPDecimalMakeZero(),
|
||||
error = CPDecimalPower(result, [self decimalValue], power, [behavior roundingMode]);
|
||||
|
||||
if (error > CPCalculationNoError)
|
||||
{
|
||||
var res = [behavior exceptionDuringOperation:_cmd error:error leftOperand:self rightOperand:[CPDecimalNumber decimalNumberWithString:power.toString()]];
|
||||
// Gnustep does this, not sure if it is correct behavior
|
||||
if (res != nil)
|
||||
return res; // say on overflow and no exception handling, returns max decimal val
|
||||
}
|
||||
return [CPDecimalNumber decimalNumberWithDecimal:result];
|
||||
}
|
||||
|
||||
- (CPDecimalNumber)decimalNumberByRoundingAccordingToBehavior:(id <CPDecimalNumberBehaviors>)behavior
|
||||
{
|
||||
var result = CPDecimalMakeZero();
|
||||
|
||||
CPDecimalRound(result, [self decimalValue], [behavior scale], [behavior roundingMode]);
|
||||
|
||||
return [CPDecimalNumber decimalNumberWithDecimal:result];
|
||||
}
|
||||
|
||||
// This method takes a CPNumber. Thus the parameter may be a CPDecimalNumber or a CPNumber class.
|
||||
// Thus the type is checked to send the operand to the correct compare function.
|
||||
- (CPComparisonResult)compare:(CPNumber)decimalNumber
|
||||
{
|
||||
if ([decimalNumber class] != CPDecimalNumber)
|
||||
decimalNumber = [CPDecimalNumber decimalNumberWithString:decimalNumber.toString()];
|
||||
return CPDecimalCompare([self decimalValue], [decimalNumber decimalValue]);
|
||||
}
|
||||
|
||||
/*!
|
||||
Unimplemented
|
||||
*/
|
||||
- (CPString)hash
|
||||
{
|
||||
objj_exception_throw("hash: NOT YET IMPLEMENTED");
|
||||
}
|
||||
|
||||
/*!
|
||||
The objective C type string. For compatability reasons
|
||||
@return returns a CPString containing "d"
|
||||
*/
|
||||
- (CPString)objCType
|
||||
{
|
||||
return @"d";
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
// FIXME: I expect here locale should be some default locale
|
||||
return [self descriptionWithLocale:nil]
|
||||
}
|
||||
|
||||
- (CPString)descriptionWithLocale:(CPDictionary)locale
|
||||
{
|
||||
return CPDecimalString(_data, locale);
|
||||
}
|
||||
|
||||
- (CPString)stringValue
|
||||
{
|
||||
return [self description];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a new CPDecimal object (which effectively contains the
|
||||
internal decimal number representation).
|
||||
@return a new CPDecimal number copy
|
||||
*/
|
||||
- (CPDecimal)decimalValue
|
||||
{
|
||||
return CPDecimalCopy(_data);
|
||||
}
|
||||
|
||||
// Type Conversion Methods
|
||||
- (double)doubleValue
|
||||
{
|
||||
// FIXME: locale support / bounds check?
|
||||
return parseFloat([self stringValue]);
|
||||
}
|
||||
|
||||
- (BOOL)boolValue
|
||||
{
|
||||
return (CPDecimalIsZero(_data))?NO:YES;
|
||||
}
|
||||
|
||||
- (char)charValue
|
||||
{
|
||||
// FIXME: locale support / bounds check?
|
||||
return parseInt([self stringValue]);
|
||||
}
|
||||
|
||||
- (float)floatValue
|
||||
{
|
||||
// FIXME: locale support / bounds check?
|
||||
return parseFloat([self stringValue]);
|
||||
}
|
||||
|
||||
- (int)intValue
|
||||
{
|
||||
// FIXME: locale support / bounds check?
|
||||
return parseInt([self stringValue]);
|
||||
}
|
||||
|
||||
- (long long)longLongValue
|
||||
{
|
||||
// FIXME: locale support / bounds check?
|
||||
return parseFloat([self stringValue]);
|
||||
}
|
||||
|
||||
- (long)longValue
|
||||
{
|
||||
// FIXME: locale support / bounds check?
|
||||
return parseInt([self stringValue]);
|
||||
}
|
||||
|
||||
- (short)shortValue
|
||||
{
|
||||
// FIXME: locale support / bounds check?
|
||||
return parseInt([self stringValue]);
|
||||
}
|
||||
|
||||
- (unsigned char)unsignedCharValue
|
||||
{
|
||||
// FIXME: locale support / bounds check?
|
||||
return parseInt([self stringValue]);
|
||||
}
|
||||
|
||||
- (unsigned int)unsignedIntValue
|
||||
{
|
||||
// FIXME: locale support / bounds check?
|
||||
return parseInt([self stringValue]);
|
||||
}
|
||||
|
||||
- (unsigned long)unsignedLongValue
|
||||
{
|
||||
// FIXME: locale support / bounds check?
|
||||
return parseInt([self stringValue]);
|
||||
}
|
||||
|
||||
- (unsigned short)unsignedShortValue
|
||||
{
|
||||
// FIXME: locale support / bounds check?
|
||||
return parseInt([self stringValue]);
|
||||
}
|
||||
|
||||
- (BOOL)isEqualToNumber:(CPNumber)aNumber
|
||||
{
|
||||
return (CPDecimalCompare(CPDecimalMakeWithString(aNumber.toString(),nil), _data) == CPOrderedSame)?YES:NO;
|
||||
}
|
||||
|
||||
// CPNumber inherited methods
|
||||
+ (id)numberWithBool:(BOOL)aBoolean
|
||||
{
|
||||
return [[self alloc] initWithBool:aBoolean];
|
||||
}
|
||||
|
||||
+ (id)numberWithChar:(char)aChar
|
||||
{
|
||||
return [[self alloc] initWithChar:aChar];
|
||||
}
|
||||
|
||||
+ (id)numberWithDouble:(double)aDouble
|
||||
{
|
||||
return [[self alloc] initWithDouble:aDouble];
|
||||
}
|
||||
|
||||
+ (id)numberWithFloat:(float)aFloat
|
||||
{
|
||||
return [[self alloc] initWithFloat:aFloat];
|
||||
}
|
||||
|
||||
+ (id)numberWithInt:(int)anInt
|
||||
{
|
||||
return [[self alloc] initWithInt:anInt];
|
||||
}
|
||||
|
||||
+ (id)numberWithLong:(long)aLong
|
||||
{
|
||||
return [[self alloc] initWithLong:aLong];
|
||||
}
|
||||
|
||||
+ (id)numberWithLongLong:(long long)aLongLong
|
||||
{
|
||||
return [[self alloc] initWithLongLong:aLongLong];
|
||||
}
|
||||
|
||||
+ (id)numberWithShort:(short)aShort
|
||||
{
|
||||
return [[self alloc] initWithShort:aShort];
|
||||
}
|
||||
|
||||
+ (id)numberWithUnsignedChar:(unsigned char)aChar
|
||||
{
|
||||
return [[self alloc] initWithUnsignedChar:aChar];
|
||||
}
|
||||
|
||||
+ (id)numberWithUnsignedInt:(unsigned)anUnsignedInt
|
||||
{
|
||||
return [[self alloc] initWithUnsignedInt:anUnsignedInt];
|
||||
}
|
||||
|
||||
+ (id)numberWithUnsignedLong:(unsigned long)anUnsignedLong
|
||||
{
|
||||
return [[self alloc] initWithUnsignedLong:anUnsignedLong];
|
||||
}
|
||||
|
||||
+ (id)numberWithUnsignedLongLong:(unsigned long)anUnsignedLongLong
|
||||
{
|
||||
return [[self alloc] initWithUnsignedLongLong:anUnsignedLongLong];
|
||||
}
|
||||
|
||||
+ (id)numberWithUnsignedShort:(unsigned short)anUnsignedShort
|
||||
{
|
||||
return [[self alloc] initWithUnsignedShort:anUnsignedShort];
|
||||
}
|
||||
|
||||
- (id)initWithBool:(BOOL)value
|
||||
{
|
||||
if (self = [self init])
|
||||
_data = CPDecimalMakeWithParts((value)?1:0, 0);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithChar:(char)value
|
||||
{
|
||||
return [self _initWithJSNumber:value];
|
||||
}
|
||||
|
||||
- (id)initWithDouble:(double)value
|
||||
{
|
||||
return [self _initWithJSNumber:value];
|
||||
}
|
||||
|
||||
- (id)initWithFloat:(float)value
|
||||
{
|
||||
return [self _initWithJSNumber:value];
|
||||
}
|
||||
|
||||
- (id)initWithInt:(int)value
|
||||
{
|
||||
return [self _initWithJSNumber:value];
|
||||
}
|
||||
|
||||
- (id)initWithLong:(long)value
|
||||
{
|
||||
return [self _initWithJSNumber:value];
|
||||
}
|
||||
|
||||
- (id)initWithLongLong:(long long)value
|
||||
{
|
||||
return [self _initWithJSNumber:value];
|
||||
}
|
||||
|
||||
- (id)initWithShort:(short)value
|
||||
{
|
||||
return [self _initWithJSNumber:value];
|
||||
}
|
||||
|
||||
- (id)initWithUnsignedChar:(unsigned char)value
|
||||
{
|
||||
return [self _initWithJSNumber:value];
|
||||
}
|
||||
|
||||
- (id)initWithUnsignedInt:(unsigned)value
|
||||
{
|
||||
return [self _initWithJSNumber:value];
|
||||
}
|
||||
|
||||
- (id)initWithUnsignedLong:(unsigned long)value
|
||||
{
|
||||
return [self _initWithJSNumber:value];
|
||||
}
|
||||
|
||||
- (id)initWithUnsignedLongLong:(unsigned long long)value
|
||||
{
|
||||
return [self _initWithJSNumber:value];
|
||||
}
|
||||
|
||||
- (id)initWithUnsignedShort:(unsigned short)value
|
||||
{
|
||||
return [self _initWithJSNumber:value];
|
||||
}
|
||||
|
||||
- (id)_initWithJSNumber:value
|
||||
{
|
||||
if (self = [self init])
|
||||
_data = CPDecimalMakeWithString(value.toString(), nil);
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -28,6 +28,8 @@
|
||||
@import "CPCompoundPredicate.j"
|
||||
@import "CPData.j"
|
||||
@import "CPDate.j"
|
||||
@import "CPDecimal.j"
|
||||
@import "CPDecimalNumber.j"
|
||||
@import "CPDictionary.j"
|
||||
@import "CPEnumerator.j"
|
||||
@import "CPException.j"
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* CPDecimalNumberHandlerTest.j
|
||||
* Foundation
|
||||
*
|
||||
* Created by Stephen Paul Ierodiaconou
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPString.j>
|
||||
@import <Foundation/CPDecimalNumber.j>
|
||||
|
||||
@implementation CPDecimalNumberHandlerTest : OJTestCase
|
||||
|
||||
- (void)testinitWithRoundingMode
|
||||
{
|
||||
var h1 = [CPDecimalNumberHandler alloc];
|
||||
|
||||
[self assertTrue:h1 message:"T1 initWithRoundingMode: failed to alloc"];
|
||||
|
||||
[h1 initWithRoundingMode:CPRoundPlain scale:3 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];
|
||||
|
||||
[self assert:3 equals:[h1 scale] message:"T1 initWithRoundingMode: scale wrong"];
|
||||
}
|
||||
|
||||
- (void)testdecimalNumberHandlerWithRoundingMode
|
||||
{
|
||||
var h1 = [CPDecimalNumberHandler decimalNumberHandlerWithRoundingMode:CPRoundPlain scale:0 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];
|
||||
|
||||
[self assertTrue:h1 message:"T1 decimalNumberHandlerWithRoundingMode: returned nil"];
|
||||
|
||||
[self assertTrue:[h1 roundingMode] message:"T1 decimalNumberHandlerWithRoundingMode: rounding mode wrong"];
|
||||
}
|
||||
|
||||
- (void)testdefaultDecimalNumberHandler
|
||||
{
|
||||
[self assert:_cappdefaultDcmHandler equals:[CPDecimalNumberHandler defaultDecimalNumberHandler] message:"T1 defaultDecimalNumberHandler returned different handler than the current default"];
|
||||
}
|
||||
|
||||
- (void)testroundingMode
|
||||
{
|
||||
var h1 = [CPDecimalNumberHandler decimalNumberHandlerWithRoundingMode:CPRoundDown scale:0 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];
|
||||
|
||||
[self assertTrue:h1 message:"T1 roundingMode: no alloc"];
|
||||
|
||||
[self assert:2 equals:[h1 roundingMode] message:"T1 roundingMode: rounding mode wrong"];
|
||||
}
|
||||
|
||||
- (void)testscale
|
||||
{
|
||||
var h1 = [CPDecimalNumberHandler decimalNumberHandlerWithRoundingMode:CPRoundDown scale:-6 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];
|
||||
|
||||
[self assertTrue:h1 message:"T1 roundingMode: no alloc"];
|
||||
|
||||
[self assert:-6 equals:[h1 scale] message:"T1 roundingMode: scale wrong"];
|
||||
}
|
||||
|
||||
- (void)testexceptionDuringOperation
|
||||
{
|
||||
var h1 = [CPDecimalNumberHandler decimalNumberHandlerWithRoundingMode:CPRoundDown scale:0 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];
|
||||
[self assertTrue:h1 message:"T1 exceptionDuringOperation: no alloc"];
|
||||
|
||||
var a = [CPDecimalNumber decimalNumberWithString:@"100"];
|
||||
var b = [CPDecimalNumber decimalNumberWithString:@"100"];
|
||||
|
||||
// no throw first
|
||||
try {
|
||||
[h1 exceptionDuringOperation:nil error:CPCalculationLossOfPrecision leftOperand:a rightOperand:b];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
[self fail:"T2 exceptionDuringOperation: Should have not thrown a precision exception"];
|
||||
}
|
||||
try {
|
||||
[h1 exceptionDuringOperation:nil error:CPCalculationOverflow leftOperand:a rightOperand:b];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
[self fail:"T3 exceptionDuringOperation: Should have not thrown an overflow exception"];
|
||||
}
|
||||
|
||||
try {
|
||||
[h1 exceptionDuringOperation:nil error:CPCalculationUnderflow leftOperand:a rightOperand:b];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
[self fail:"T4 exceptionDuringOperation: Should have not thrown an underflow exception"];
|
||||
}
|
||||
try {
|
||||
[h1 exceptionDuringOperation:nil error:CPCalculationDivideByZero leftOperand:a rightOperand:b];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
[self fail:"T5 exceptionDuringOperation: Should have not thrown a div by zero exception"];
|
||||
}
|
||||
|
||||
// now throw
|
||||
h1 = [CPDecimalNumberHandler decimalNumberHandlerWithRoundingMode:CPRoundDown scale:0 raiseOnExactness:YES raiseOnOverflow:YES raiseOnUnderflow:YES raiseOnDivideByZero:YES];
|
||||
try {
|
||||
[h1 exceptionDuringOperation:nil error:CPCalculationLossOfPrecision leftOperand:a rightOperand:b];
|
||||
[self fail:"T6 exceptionDuringOperation: Should have thrown a precision exception"];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
try {
|
||||
[h1 exceptionDuringOperation:nil error:CPCalculationOverflow leftOperand:a rightOperand:b];
|
||||
[self fail:"T3 exceptionDuringOperation: Should have thrown an overflow exception"];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
try {
|
||||
[h1 exceptionDuringOperation:nil error:CPCalculationUnderflow leftOperand:a rightOperand:b];
|
||||
[self fail:"T4 exceptionDuringOperation: Should have thrown an underflow exception"];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
try {
|
||||
[h1 exceptionDuringOperation:nil error:CPCalculationDivideByZero leftOperand:a rightOperand:b];
|
||||
[self fail:"T5 exceptionDuringOperation: Should have thrown a div by zero exception"];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,535 @@
|
||||
/*
|
||||
* CPDecimalNumberTest.j
|
||||
* Foundation
|
||||
*
|
||||
* Created by Stephen Paul Ierodiaconou
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPString.j>
|
||||
@import <Foundation/CPDecimalNumber.j>
|
||||
|
||||
@implementation CPDecimalNumberTest : OJTestCase
|
||||
{
|
||||
CPDecimalNumberHandler _dcmnh;
|
||||
CPDecimalNumberHandler _dcmnhWithExactness;
|
||||
}
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
if (!_dcmnh)
|
||||
_dcmnh = [CPDecimalNumberHandler decimalNumberHandlerWithRoundingMode:CPRoundPlain scale:0 raiseOnExactness:NO raiseOnOverflow:YES raiseOnUnderflow:YES raiseOnDivideByZero:YES];
|
||||
if (!_dcmnhWithExactness)
|
||||
_dcmnhWithExactness = [CPDecimalNumberHandler decimalNumberHandlerWithRoundingMode:CPRoundPlain scale:0 raiseOnExactness:YES raiseOnOverflow:YES raiseOnUnderflow:YES raiseOnDivideByZero:YES];
|
||||
}
|
||||
|
||||
// init
|
||||
- (void)testInitialisersAndMisc
|
||||
{
|
||||
// CPDecimalNumber class initialisers
|
||||
var dcmn = [[CPDecimalNumber alloc] initWithString:@"10.72342"];
|
||||
var dcm = [dcmn decimalValue];
|
||||
[self assert:-5 equals:dcm._exponent message:"initWithString: - exponent"];
|
||||
[self assert:[1,0,7,2,3,4,2] equals:dcm._mantissa message:"initWithString: - mantissa"];
|
||||
[self assert:NO equals:dcm._isNegative message:"initWithString: - sign"];
|
||||
[self assert:NO equals:dcm._isNaN message:"initWithString: - NaN is incorrectly set"];
|
||||
|
||||
dcmn = [[CPDecimalNumber alloc] initWithString:@"0.000001e18" locale:nil];
|
||||
dcm = [dcmn decimalValue];
|
||||
[self assert:12 equals:dcm._exponent message:"initWithString:locale: - exponent"];
|
||||
[self assert:[1] equals:dcm._mantissa message:"initWithString:locale: mantissa"];
|
||||
[self assert:NO equals:dcm._isNegative message:"initWithString:locale: sign"];
|
||||
[self assert:NO equals:dcm._isNaN message:"initWithString:locale: NaN is incorrectly set"];
|
||||
|
||||
dcmn = [CPDecimalNumber decimalNumberWithString:@"-578e-2"];
|
||||
dcm = [dcmn decimalValue];
|
||||
[self assert:-2 equals:dcm._exponent message:"decimalNumberWithString: - exponent"];
|
||||
[self assert:[5,7,8] equals:dcm._mantissa message:"decimalNumberWithString: - mantissa"];
|
||||
[self assert:YES equals:dcm._isNegative message:"decimalNumberWithString: - sign"];
|
||||
[self assert:NO equals:dcm._isNaN message:"decimalNumberWithString: - NaN is incorrectly set"];
|
||||
|
||||
dcmn = [CPDecimalNumber decimalNumberWithString:@"-0.0001e-5" locale:nil];
|
||||
dcm = [dcmn decimalValue];
|
||||
[self assert:-9 equals:dcm._exponent message:"decimalNumberWithString:locale: - exponent"];
|
||||
[self assert:[1] equals:dcm._mantissa message:"decimalNumberWithString:locale: - mantissa"];
|
||||
[self assert:YES equals:dcm._isNegative message:"decimalNumberWithString:locale: - sign"];
|
||||
[self assert:NO equals:dcm._isNaN message:"decimalNumberWithString:locale: - NaN is incorrectly set"];
|
||||
|
||||
dcmn = [[CPDecimalNumber alloc] initWithDecimal:dcm];
|
||||
dcm = [dcmn decimalValue];
|
||||
[self assert:-9 equals:dcm._exponent message:"initWithDecimal: - exponent"];
|
||||
[self assert:[1] equals:dcm._mantissa message:"initWithDecimal: - mantissa"];
|
||||
[self assert:YES equals:dcm._isNegative message:"initWithDecimal: - sign"];
|
||||
|
||||
dcmn = [CPDecimalNumber decimalNumberWithDecimal:dcm];
|
||||
dcm = [dcmn decimalValue];
|
||||
[self assert:-9 equals:dcm._exponent message:"decimalNumberWithDecimal: - exponent"];
|
||||
[self assert:[1] equals:dcm._mantissa message:"decimalNumberWithDecimal: - mantissa"];
|
||||
[self assert:YES equals:dcm._isNegative message:"decimalNumberWithDecimal: - sign"];
|
||||
|
||||
dcmn = [[CPDecimalNumber alloc] initWithMantissa:123654 exponent:19 isNegative:YES];
|
||||
dcm = [dcmn decimalValue];
|
||||
[self assert:19 equals:dcm._exponent message:"initWithMantissa:exponent:isNegative: - exponent"];
|
||||
[self assert:[1,2,3,6,5,4] equals:dcm._mantissa message:"initWithMantissa:exponent:isNegative: - mantissa"];
|
||||
[self assert:YES equals:dcm._isNegative message:"initWithMantissa:exponent:isNegative: - sign"];
|
||||
|
||||
dcmn = [CPDecimalNumber decimalNumberWithMantissa:9876543 exponent:2 isNegative:NO];
|
||||
dcm = [dcmn decimalValue];
|
||||
[self assert:2 equals:dcm._exponent message:"decimalNumberWithMantissa:exponent:isNegative: - exponent"];
|
||||
[self assert:[9,8,7,6,5,4,3] equals:dcm._mantissa message:"decimalNumberWithMantissa:exponent:isNegative: - mantissa"];
|
||||
[self assert:NO equals:dcm._isNegative message:"decimalNumberWithMantissa:exponent:isNegative: - sign"];
|
||||
|
||||
// Def behavior
|
||||
[self assert:[CPDecimalNumber defaultBehavior] equals:_cappdefaultDcmHandler message:"defaultBehavior: - returned different object"];
|
||||
|
||||
[CPDecimalNumber setDefaultBehavior:_dcmnhWithExactness];
|
||||
[self assertTrue:[CPDecimalNumber defaultBehavior]._raiseOnExactness message:"setDefaultBehavior: - new behavior not set"];
|
||||
[CPDecimalNumber setDefaultBehavior:_dcmnh];
|
||||
|
||||
// Range and special values
|
||||
dcmn = [CPDecimalNumber maximumDecimalNumber];
|
||||
dcm = [dcmn decimalValue];
|
||||
[self assert:CPDecimalMaxExponent equals:dcm._exponent message:"maximumDecimalNumber: - exponent"];
|
||||
[self assert:[9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9] equals:dcm._mantissa message:"maximumDecimalNumber: - mantissa"];
|
||||
[self assert:NO equals:dcm._isNegative message:"maximumDecimalNumber: - sign"];
|
||||
|
||||
dcmn = [CPDecimalNumber minimumDecimalNumber];
|
||||
dcm = [dcmn decimalValue];
|
||||
[self assert:CPDecimalMinExponent equals:dcm._exponent message:"minimumDecimalNumber: - exponent"];
|
||||
[self assert:[9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9] equals:dcm._mantissa message:"minimumDecimalNumber: - mantissa"];
|
||||
[self assert:YES equals:dcm._isNegative message:"minimumDecimalNumber: - sign"];
|
||||
|
||||
dcmn = [CPDecimalNumber notANumber];
|
||||
dcm = [dcmn decimalValue];
|
||||
[self assert:YES equals:dcm._isNaN message:"notANumber: - NaN should be YES"];
|
||||
|
||||
dcmn = [CPDecimalNumber one];
|
||||
dcm = [dcmn decimalValue];
|
||||
[self assert:0 equals:dcm._exponent message:"one: - exponent"];
|
||||
[self assert:[1] equals:dcm._mantissa message:"one: - mantissa"];
|
||||
[self assert:NO equals:dcm._isNegative message:"one: - sign"];
|
||||
|
||||
dcmn = [CPDecimalNumber zero];
|
||||
dcm = [dcmn decimalValue];
|
||||
[self assert:0 equals:dcm._exponent message:"zero: - exponent"];
|
||||
[self assert:[0] equals:dcm._mantissa message:"zero: - mantissa"];
|
||||
[self assert:NO equals:dcm._isNegative message:"zero: - sign"];
|
||||
|
||||
|
||||
// misc
|
||||
// decimalValue <- if it hasnt been working so far, your would know.
|
||||
|
||||
dcmn = [CPDecimalNumber zero];
|
||||
dcm = [dcmn boolValue];
|
||||
[self assert:false equals:dcm message:"boolValue: - should be false"];
|
||||
dcmn = [CPDecimalNumber decimalNumberWithString:@"578"];
|
||||
dcm = [dcmn boolValue];
|
||||
[self assert:true equals:dcm message:"boolValue: - should be true"];
|
||||
|
||||
// exceptions
|
||||
try {
|
||||
dcmn = [[CPDecimalNumber alloc] initWithString:@"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"];
|
||||
[self fail:"initWithString: TEX1: overflow from string"];
|
||||
} catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
try {
|
||||
dcmn = [[CPDecimalNumber alloc] initWithString:@"foo"];
|
||||
[self fail:"initWithString: TEX2: invalid string"];
|
||||
} catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
try {
|
||||
dcmn = [[CPDecimalNumber alloc] initWithString:@".123"];
|
||||
[self fail:"initWithString: TEX3: invalid string"];
|
||||
} catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
try {
|
||||
dcmn = [[CPDecimalNumber alloc] initWithString:@"-.123"];
|
||||
[self fail:"initWithString: TEX4: invalid string"];
|
||||
} catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
try {
|
||||
dcmn = [[CPDecimalNumber alloc] initWithString:@"0123"];
|
||||
[self fail:"initWithString: TEX5: invalid string"];
|
||||
} catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
try {
|
||||
dcmn = [[CPDecimalNumber alloc] initWithString:@"1e200"];
|
||||
[self fail:"initWithString: TEX6: exponent overflow"];
|
||||
} catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
try{
|
||||
dcmn = [[CPDecimalNumber alloc] initWithString:@"12312e-23421"];
|
||||
[self fail:"initWithString: TEX7: exponent underflow"];
|
||||
} catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testAdd
|
||||
{
|
||||
|
||||
var dcmn1 = [CPDecimalNumber decimalNumberWithString:@"123"];
|
||||
var dcmn2 = [CPDecimalNumber decimalNumberWithString:@"321"];
|
||||
var dcmn3 = [dcmn1 decimalNumberByAdding:dcmn2];
|
||||
var d1 = [dcmn3 decimalValue];
|
||||
[self assert:0 equals:d1._exponent message:"decimalNumberByAdding: - exponent"];
|
||||
[self assert:[4,4,4] equals:d1._mantissa message:"decimalNumberByAdding: - mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"decimalNumberByAdding: - sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"decimalNumberByAdding: - NaN is incorrectly set"];
|
||||
|
||||
// precision throw - with behavior
|
||||
dcmn1 = [CPDecimalNumber decimalNumberWithString:@"10000000000000000000000000000000000001"];
|
||||
dcmn2 = [CPDecimalNumber decimalNumberWithString:@"1.00001"];
|
||||
try {
|
||||
dcmn3 = [dcmn1 decimalNumberByAdding:dcmn2 withBehavior:_dcmnhWithExactness];
|
||||
[self fail:"decimalNumberByAdding:withBehavior: TEX1 - should have throw precision error "];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
try {
|
||||
dcmn3 = [dcmn1 decimalNumberByAdding:dcmn2];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
[self fail:"decimalNumberByAdding: TEX2 - should not have thrown precision error "];
|
||||
}
|
||||
|
||||
// overflow
|
||||
dcmn1 = [CPDecimalNumber maximumDecimalNumber];
|
||||
dcmn2 = [CPDecimalNumber maximumDecimalNumber];
|
||||
try {
|
||||
dcmn3 = [dcmn1 decimalNumberByAdding:dcmn2];
|
||||
[self fail:"decimalNumberByAdding: TEX3 - should have thrown overflow error "];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (void)testSubtract
|
||||
{
|
||||
var dcmn1 = [CPDecimalNumber decimalNumberWithString:@"301"];
|
||||
var dcmn2 = [CPDecimalNumber decimalNumberWithString:@"153"];
|
||||
var dcmn3 = [dcmn1 decimalNumberBySubtracting:dcmn2];
|
||||
var d1 = [dcmn3 decimalValue];
|
||||
[self assert:0 equals:d1._exponent message:"decimalNumberBySubtracting: - exponent"];
|
||||
[self assert:[1,4,8] equals:d1._mantissa message:"decimalNumberBySubtracting: - mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"decimalNumberBySubtracting: - sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"decimalNumberBySubtracting: - NaN is incorrectly set"];
|
||||
|
||||
// precision throw - with behavior
|
||||
dcmn1 = [CPDecimalNumber decimalNumberWithString:@"1e-128"];
|
||||
dcmn2 = [CPDecimalNumber decimalNumberWithString:@"1"];
|
||||
try {
|
||||
dcmn3 = [dcmn1 decimalNumberBySubtracting:dcmn2 withBehavior:_dcmnhWithExactness];
|
||||
[self fail:"decimalNumberBySubtracting:withBehavior: TEX1 - should have throw precision error "];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
try {
|
||||
dcmn3 = [dcmn1 decimalNumberBySubtracting:dcmn2];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
[self fail:"decimalNumberBySubtracting: TEX2 - should not have thrown precision error "];
|
||||
}
|
||||
|
||||
// can we get underflow from subtraction since we cant represent anything smaller than the allowed range anyway?
|
||||
}
|
||||
|
||||
- (void)testDivide
|
||||
{
|
||||
var dcmn1 = [CPDecimalNumber decimalNumberWithString:@"7126313"];
|
||||
var dcmn2 = [CPDecimalNumber decimalNumberWithString:@"1235"];
|
||||
var dcmn3 = [dcmn1 decimalNumberByDividingBy:dcmn2];
|
||||
var d1 = [dcmn3 decimalValue];
|
||||
[self assert:-34 equals:d1._exponent message:"decimalNumberByDividingBy: - exponent"];
|
||||
[self assert:[5,7,7,0,2,9,3,9,2,7,1,2,5,5,0,6,0,7,2,8,7,4,4,9,3,9,2,7,1,2,5,5,0,6,0,7,2,8] equals:d1._mantissa message:"decimalNumberByDividingBy: T1: mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"decimalNumberByDividingBy: - sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"decimalNumberByDividingBy: - NaN is incorrectly set"];
|
||||
|
||||
dcmn1 = [CPDecimalNumber decimalNumberWithString:@"1"];
|
||||
dcmn2 = [CPDecimalNumber decimalNumberWithString:@"2"];
|
||||
dcmn3 = [dcmn1 decimalNumberByDividingBy:dcmn2 withBehavior:_dcmnhWithExactness];
|
||||
d1 = [dcmn3 decimalValue];
|
||||
[self assert:-1 equals:d1._exponent message:"decimalNumberByDividingBy:withBehavior: - exponent"];
|
||||
[self assert:[5] equals:d1._mantissa message:"decimalNumberByDividingBy:withBehavior: - mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"decimalNumberByDividingBy:withBehavior: - sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"decimalNumberByDividingBy:withBehavior: - NaN is incorrectly set"];
|
||||
|
||||
// Exceptions
|
||||
dcmn1 = [CPDecimalNumber decimalNumberWithString:@"1"];
|
||||
dcmn2 = [CPDecimalNumber decimalNumberWithString:@"3"];
|
||||
try {
|
||||
dcmn3 = [dcmn1 decimalNumberByDividingBy:dcmn2 withBehavior:_dcmnhWithExactness];
|
||||
[self fail:"decimalNumberByDividingBy:withBehavior: TEX1 - should have thrown precision error "];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
try {
|
||||
dcmn3 = [dcmn1 decimalNumberByDividingBy:dcmn2];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
[self fail:"decimalNumberByDividingBy: TEX2 - should not have thrown precision error "];
|
||||
}
|
||||
|
||||
// underflow , if dcnm2 is < 10 this is LossOfPrecision, is this correct? check vs cocoa.
|
||||
dcmn1 = [CPDecimalNumber decimalNumberWithString:@"-1e-128"];
|
||||
dcmn2 = [CPDecimalNumber decimalNumberWithString:@"10"];
|
||||
try {
|
||||
dcmn3 = [dcmn1 decimalNumberByDividingBy:dcmn2];
|
||||
[self fail:"decimalNumberByDividingBy: TEX3 - should have thrown underflow error "];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
|
||||
dcmn1 = [CPDecimalNumber decimalNumberWithString:@"-1e-128"];
|
||||
dcmn2 = [CPDecimalNumber decimalNumberWithString:@"0"];
|
||||
try {
|
||||
dcmn3 = [dcmn1 decimalNumberByDividingBy:dcmn2];
|
||||
[self fail:"decimalNumberByDividingBy: TEX3 - should have thrown DIV0 error "];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
*/
|
||||
- (void)testMutliply
|
||||
{
|
||||
|
||||
var dcmn1 = [CPDecimalNumber decimalNumberWithString:@"17"];
|
||||
var dcmn2 = [CPDecimalNumber decimalNumberWithString:@"512"];
|
||||
var dcmn3 = [dcmn1 decimalNumberByMultiplyingBy:dcmn2];
|
||||
var d1 = [dcmn3 decimalValue];
|
||||
[self assert:0 equals:d1._exponent message:"decimalNumberByMultiplyingBy: - exponent"];
|
||||
[self assert:[8,7,0,4] equals:d1._mantissa message:"decimalNumberByMultiplyingBy: - mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"decimalNumberByMultiplyingBy: - sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"decimalNumberByMultiplyingBy: - NaN is incorrectly set"];
|
||||
|
||||
dcmn1 = [CPDecimalNumber decimalNumberWithString:@"0.0001"];
|
||||
dcmn2 = [CPDecimalNumber decimalNumberWithString:@"1024"];
|
||||
dcmn3 = [dcmn1 decimalNumberByMultiplyingBy:dcmn2 withBehavior:_dcmnhWithExactness];
|
||||
d1 = [dcmn3 decimalValue];
|
||||
[self assert:-4 equals:d1._exponent message:"decimalNumberByMultiplyingBy:withBehavior: - exponent"];
|
||||
[self assert:[1,0,2,4] equals:d1._mantissa message:"decimalNumberByMultiplyingBy:withBehavior: - mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"decimalNumberByMultiplyingBy:withBehavior: - sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"decimalNumberByMultiplyingBy:withBehavior: - NaN is incorrectly set"];
|
||||
|
||||
// Exceptions
|
||||
dcmn1 = [CPDecimalNumber decimalNumberWithString:@"18302741890374918"];
|
||||
dcmn2 = [CPDecimalNumber decimalNumberWithString:@"123847190277982223422346878934534"];
|
||||
try {
|
||||
dcmn3 = [dcmn1 decimalNumberByMultiplyingBy:dcmn2 withBehavior:_dcmnhWithExactness];
|
||||
[self fail:"decimalNumberByMultiplyingBy:withBehavior: TEX1 - should have thrown precision error "];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
try {
|
||||
dcmn3 = [dcmn1 decimalNumberByMultiplyingBy:dcmn2];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
[self fail:"decimalNumberByMultiplyingBy: TEX2 - should not have thrown precision error "];
|
||||
}
|
||||
|
||||
// overflow
|
||||
dcmn1 = [CPDecimalNumber decimalNumberWithString:@"23e100"];
|
||||
dcmn2 = [CPDecimalNumber decimalNumberWithString:@"-13e76"];
|
||||
try {
|
||||
dcmn3 = [dcmn1 decimalNumberByMultiplyingBy:dcmn2];
|
||||
[self fail:"decimalNumberByMultiplyingBy: TEX3 - should have overflowed "];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testPower10
|
||||
{
|
||||
var dcmn1 = [CPDecimalNumber decimalNumberWithString:@"17"];
|
||||
var p = 21;
|
||||
var dcmn3 = [dcmn1 decimalNumberByMultiplyingByPowerOf10:p];
|
||||
var d1 = [dcmn3 decimalValue];
|
||||
[self assert:21 equals:d1._exponent message:"decimalNumberByMultiplyingByPowerOf10: - exponent"];
|
||||
[self assert:[1,7] equals:d1._mantissa message:"decimalNumberByMultiplyingByPowerOf10: - mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"decimalNumberByMultiplyingByPowerOf10: - sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"decimalNumberByMultiplyingByPowerOf10: - NaN is incorrectly set"];
|
||||
|
||||
dcmn1 = [CPDecimalNumber decimalNumberWithString:@"1e121"];
|
||||
p = -123;
|
||||
dcmn3 = [dcmn1 decimalNumberByMultiplyingByPowerOf10:p withBehavior:_dcmnhWithExactness];
|
||||
d1 = [dcmn3 decimalValue];
|
||||
[self assert:-2 equals:d1._exponent message:"decimalNumberByMultiplyingByPowerOf10:withBehavior: - exponent"];
|
||||
[self assert:[1] equals:d1._mantissa message:"decimalNumberByMultiplyingByPowerOf10:withBehavior: - mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"decimalNumberByMultiplyingByPowerOf10:withBehavior: - sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"decimalNumberByMultiplyingByPowerOf10:withBehavior: - NaN is incorrectly set"];
|
||||
|
||||
// Exceptions
|
||||
// overflow
|
||||
dcmn1 = [CPDecimalNumber decimalNumberWithString:@"1e23"];
|
||||
p = 127;
|
||||
try {
|
||||
dcmn3 = [dcmn1 decimalNumberByMultiplyingByPowerOf10:p];
|
||||
[self fail:"decimalNumberByMultiplyingByPowerOf10: TEX1 - should have overflowed "];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (void)testPower
|
||||
{
|
||||
var dcmn1 = [CPDecimalNumber decimalNumberWithString:@"17"];
|
||||
var p = 10;
|
||||
var dcmn3 = [dcmn1 decimalNumberByRaisingToPower:p];
|
||||
var d1 = [dcmn3 decimalValue];
|
||||
[self assert:0 equals:d1._exponent message:"decimalNumberByRaisingToPower: - exponent"];
|
||||
[self assert:[2,0,1,5,9,9,3,9,0,0,4,4,9] equals:d1._mantissa message:"decimalNumberByRaisingToPower: - mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"decimalNumberByRaisingToPower: - sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"decimalNumberByRaisingToPower: - NaN is incorrectly set"];
|
||||
|
||||
dcmn1 = [CPDecimalNumber decimalNumberWithString:@"54"];
|
||||
p = 2;
|
||||
dcmn3 = [dcmn1 decimalNumberByRaisingToPower:p withBehavior:_dcmnhWithExactness];
|
||||
d1 = [dcmn3 decimalValue];
|
||||
[self assert:0 equals:d1._exponent message:"decimalNumberByRaisingToPower:withBehavior: - exponent"];
|
||||
[self assert:[2,9,1,6] equals:d1._mantissa message:"decimalNumberByRaisingToPower:withBehavior: - mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"decimalNumberByRaisingToPower:withBehavior: - sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"decimalNumberByRaisingToPower:withBehavior: - NaN is incorrectly set"];
|
||||
|
||||
// Exceptions
|
||||
dcmn1 = [CPDecimalNumber decimalNumberWithString:@"123198771093489073413"];
|
||||
p = 2;
|
||||
try {
|
||||
dcmn3 = [dcmn1 decimalNumberByRaisingToPower:p withBehavior:_dcmnhWithExactness];
|
||||
[self fail:"decimalNumberByRaisingToPower:withBehavior: TEX1 - should have thrown precision error "];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
try {
|
||||
dcmn3 = [dcmn1 decimalNumberByRaisingToPower:p];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
[self fail:"decimalNumberByRaisingToPower: TEX2 - should not have thrown precision error "];
|
||||
}
|
||||
|
||||
// overflow
|
||||
dcmn1 = [CPDecimalNumber decimalNumberWithString:@"1234"];
|
||||
p = 123;
|
||||
try {
|
||||
dcmn3 = [dcmn1 decimalNumberByRaisingToPower:p];
|
||||
[self fail:"decimalNumberByRaisingToPower: TEX3 - should have overflowed "];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
if ((e.isa) && [e name] == AssertionFailedError)
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testRounding
|
||||
{
|
||||
var h = [CPDecimalNumberHandler decimalNumberHandlerWithRoundingMode:CPRoundDown scale:0 raiseOnExactness:NO raiseOnOverflow:YES raiseOnUnderflow:YES raiseOnDivideByZero:YES];
|
||||
var dcmn1 = [CPDecimalNumber decimalNumberWithString:@"1.4"];
|
||||
var dcmn3 = [dcmn1 decimalNumberByRoundingAccordingToBehavior:h];
|
||||
var d1 = [dcmn3 decimalValue];
|
||||
[self assert:0 equals:d1._exponent message:"decimalNumberByRoundingAccordingToBehavior: - exponent"];
|
||||
[self assert:[1] equals:d1._mantissa message:"decimalNumberByRoundingAccordingToBehavior: - mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"decimalNumberByRoundingAccordingToBehavior: - sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"decimalNumberByRoundingAccordingToBehavior: - NaN is incorrectly set"];
|
||||
}
|
||||
|
||||
- (void)testCompare
|
||||
{
|
||||
var dcmn1 = [CPDecimalNumber decimalNumberWithString:@"17"];
|
||||
var dcmn2 = [CPDecimalNumber decimalNumberWithString:@"512"];
|
||||
var c = [dcmn1 compare:dcmn2];
|
||||
[self assert:c equals:CPOrderedAscending message:"compare: - ascending"];
|
||||
|
||||
dcmn1 = [CPDecimalNumber decimalNumberWithString:@"1234"];
|
||||
dcmn2 = [CPDecimalNumber decimalNumberWithString:@"512"];
|
||||
c = [dcmn1 compare:dcmn2];
|
||||
[self assert:c equals:CPOrderedDescending message:"compare: - descending"];
|
||||
|
||||
dcmn1 = [CPDecimalNumber decimalNumberWithString:@"54e123"];
|
||||
dcmn2 = [CPDecimalNumber decimalNumberWithString:@"54e123"];
|
||||
c = [dcmn1 compare:dcmn2];
|
||||
[self assert:c equals:CPOrderedSame message:"compare: - same"];
|
||||
}
|
||||
|
||||
- (void)testStringValue
|
||||
{
|
||||
var dcmn = [CPDecimalNumber decimalNumberWithString:@"512"];
|
||||
[self assert:"512" equals:[dcmn stringValue] message:"stringValue: - small number"];
|
||||
dcmn = [CPDecimalNumber decimalNumberWithString:@"10823478917236482"];
|
||||
[self assert:"10823478917236482" equals:[dcmn stringValue] message:"stringValue: - medium number"];
|
||||
dcmn = [CPDecimalNumber decimalNumberWithString:@"123456789123456789123456789e15"];
|
||||
[self assert:"123456789123456789123456789000000000000000" equals:[dcmn stringValue] message:"stringValue: - large number"];
|
||||
dcmn = [CPDecimalNumber decimalNumberWithString:@"82346.2341144"];
|
||||
[self assert:"82346.2341144" equals:[dcmn descriptionWithLocale:nil] message:"descriptionWithLocale: - large number"];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,645 @@
|
||||
/*
|
||||
* CPDecimalTest.j
|
||||
* Foundation
|
||||
*
|
||||
* Created by Stephen Paul Ierodiaconou
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPString.j>
|
||||
@import <Foundation/CPDecimal.j>
|
||||
|
||||
@implementation CPDecimalTest : OJTestCase
|
||||
|
||||
- (void)testInitialisers
|
||||
{
|
||||
// max digits
|
||||
[self assertNotNull:CPDecimalMakeWithString(@"9999999999999999999999999999999999") message:"CPDecimalMakeWithString() Tmx1: max digits string"];
|
||||
[self assertNotNull:CPDecimalMakeWithString(@"-1111111111111111111111111111111111") message:"CPDecimalMakeWithString() Tmx2: negative max digits string"];
|
||||
|
||||
// too big digit, round
|
||||
var dcm = CPDecimalMakeWithString(@"11111111111111111111111111111111111111111");
|
||||
[self assertNotNull:dcm message:"CPDecimalMakeWithString() Tb1: mantissa rounding string"];
|
||||
[self assert:3 equals:dcm._exponent message:"CPDecimalMakeWithString() Tb1: exponent"];
|
||||
[self assert:[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1] equals:dcm._mantissa message:"CPDecimalMakeWithString() Tb1: mantissa"];
|
||||
[self assert:NO equals:dcm._isNegative message:"CPDecimalMakeWithString() Tb1: sign"];
|
||||
[self assert:NO equals:dcm._isNaN message:"CPDecimalMakeWithString() Tb1: NaN is incorrectly set"];
|
||||
|
||||
// format tests
|
||||
dcm = CPDecimalMakeWithString(@"+0.01e+1");
|
||||
[self assertNotNull:dcm message:"CPDecimalMakeWithString() Tf1: mantissa rounding string"];
|
||||
[self assert:-1 equals:dcm._exponent message:"CPDecimalMakeWithString() Tf1: exponent"];
|
||||
[self assert:[1] equals:dcm._mantissa message:"CPDecimalMakeWithString() Tf1: mantissa"];
|
||||
[self assert:NO equals:dcm._isNegative message:"CPDecimalMakeWithString() Tf1: sign"];
|
||||
[self assert:NO equals:dcm._isNaN message:"CPDecimalMakeWithString() Tf1: NaN is incorrectly set"];
|
||||
|
||||
dcm = CPDecimalMakeWithString(@"+99e-5");
|
||||
[self assertNotNull:dcm message:"CPDecimalMakeWithString() Tf2: mantissa rounding string"];
|
||||
[self assert:-5 equals:dcm._exponent message:"CPDecimalMakeWithString() Tf2: exponent"];
|
||||
[self assert:[9,9] equals:dcm._mantissa message:"CPDecimalMakeWithString() Tf2: mantissa"];
|
||||
[self assert:NO equals:dcm._isNegative message:"CPDecimalMakeWithString() Tf2: sign"];
|
||||
[self assert:NO equals:dcm._isNaN message:"CPDecimalMakeWithString() Tf2: NaN is incorrectly set"];
|
||||
|
||||
dcm = CPDecimalMakeWithString(@"-1234.5678e100");
|
||||
[self assertNotNull:dcm message:"CPDecimalMakeWithString() Tf3: mantissa rounding string"];
|
||||
[self assert:96 equals:dcm._exponent message:"CPDecimalMakeWithString() Tf3: exponent"];
|
||||
[self assert:[1,2,3,4,5,6,7,8] equals:dcm._mantissa message:"CPDecimalMakeWithString() Tf3: mantissa"];
|
||||
[self assert:YES equals:dcm._isNegative message:"CPDecimalMakeWithString() Tf3: sign"];
|
||||
[self assert:NO equals:dcm._isNaN message:"CPDecimalMakeWithString() Tf3: NaN is incorrectly set"];
|
||||
|
||||
dcm = CPDecimalMakeWithString(@"0.00000000000000000000000001");
|
||||
[self assertNotNull:dcm message:"CPDecimalMakeWithString() Tf4: mantissa rounding string"];
|
||||
[self assert:-26 equals:dcm._exponent message:"CPDecimalMakeWithString() Tf4: exponent"];
|
||||
[self assert:[1] equals:dcm._mantissa message:"CPDecimalMakeWithString() Tf4: mantissa"];
|
||||
[self assert:NO equals:dcm._isNegative message:"CPDecimalMakeWithString() Tf4: sign"];
|
||||
[self assert:NO equals:dcm._isNaN message:"CPDecimalMakeWithString() Tf4: NaN is incorrectly set"];
|
||||
|
||||
dcm = CPDecimalMakeWithString(@"000000000000000000");
|
||||
[self assertNull:dcm message:"CPDecimalMakeWithString() Tf5: Should be invalid"];
|
||||
|
||||
// too large return nil
|
||||
[self assertNull:CPDecimalMakeWithString(@"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111") message:"CPDecimalMakeWithString() To1: number overflow handling"];
|
||||
[self assertNull:CPDecimalMakeWithString(@"-1e1000") message:"CPDecimalMakeWithString() To2: exponent overflow not caught"];
|
||||
[self assertNull:CPDecimalMakeWithString(@"-1e-2342") message:"CPDecimalMakeWithString() To3: exponent underflow not caught"];
|
||||
|
||||
// Tests for invalid strings
|
||||
[self assertNull:CPDecimalMakeWithString(@"abc") message:"CPDecimalMakeWithString() Ti1: catch of invalid number string"];
|
||||
[self assertNull:CPDecimalMakeWithString(@"123a") message:"CPDecimalMakeWithString() Ti2: catch of invalid number string"];
|
||||
[self assertNull:CPDecimalMakeWithString(@"12.7e") message:"CPDecimalMakeWithString() Ti3: catch of invalid number string"];
|
||||
[self assertNull:CPDecimalMakeWithString(@"e") message:"CPDecimalMakeWithString() Ti4: catch of invalid number string"];
|
||||
[self assertNull:CPDecimalMakeWithString(@"12 ") message:"CPDecimalMakeWithString() Ti5: catch of invalid number string"];
|
||||
[self assertNull:CPDecimalMakeWithString(@"1 2 3") message:"CPDecimalMakeWithString() Ti6: catch of invalid number string"];
|
||||
[self assertNull:CPDecimalMakeWithString(@"e10") message:"CPDecimalMakeWithString() Ti7: catch of invalid number string"];
|
||||
[self assertNull:CPDecimalMakeWithString(@"123ee") message:"CPDecimalMakeWithString() Ti8: catch of invalid number string"];
|
||||
[self assertNull:CPDecimalMakeWithString(@"0001") message:"CPDecimalMakeWithString() Ti9: catch of invalid number string"];
|
||||
[self assertNull:CPDecimalMakeWithString(@"-0001") message:"CPDecimalMakeWithString() Ti10: catch of invalid number string"];
|
||||
[self assertNull:CPDecimalMakeWithString(@".123") message:"CPDecimalMakeWithString() Ti11: catch of invalid number string"];
|
||||
[self assertNull:CPDecimalMakeWithString(@"-.1") message:"CPDecimalMakeWithString() Ti12: catch of invalid number string"];
|
||||
|
||||
//test make with parts
|
||||
dcm = CPDecimalMakeWithParts(10127658,2);
|
||||
[self assert:2 equals:dcm._exponent message:"CPDecimalMakeWithParts() Tmp1: exponent"];
|
||||
[self assert:[1,0,1,2,7,6,5,8] equals:dcm._mantissa message:"CPDecimalMakeWithParts() Tmp1: mantissa"];
|
||||
[self assert:NO equals:dcm._isNegative message:"CPDecimalMakeWithParts() Tmp1: sign"];
|
||||
[self assert:NO equals:dcm._isNaN message:"CPDecimalMakeWithParts() Tmp1: NaN is incorrectly set"];
|
||||
dcm = CPDecimalMakeWithParts(-1000000,0);
|
||||
[self assert:6 equals:dcm._exponent message:"CPDecimalMakeWithParts() Tmp2: exponent"];
|
||||
[self assert:[1] equals:dcm._mantissa message:"CPDecimalMakeWithParts() Tmp2: mantissa"];
|
||||
[self assert:YES equals:dcm._isNegative message:"CPDecimalMakeWithParts() Tmp2: sign"];
|
||||
[self assert:NO equals:dcm._isNaN message:"CPDecimalMakeWithParts() Tmp2: NaN is incorrectly set"];
|
||||
|
||||
[self assertNull:CPDecimalMakeWithParts(1,10000) message:"CPDecimalMakeWithParts() Tmp3: exponent overflow not caught"];
|
||||
[self assertNull:CPDecimalMakeWithParts(-1,-1000) message:"CPDecimalMakeWithParts() Tmp4: exponent underflow not caught"];
|
||||
}
|
||||
|
||||
- (void)testZeros
|
||||
{
|
||||
var dcm = CPDecimalMakeWithString(@"0");
|
||||
[self assertTrue:CPDecimalIsZero(dcm) message:"CPDecimalMakeWithString(0) and CPDecimalIsZero()"];
|
||||
dcm = CPDecimalMakeWithString(@"-0.000000000000e-0");
|
||||
[self assertTrue:CPDecimalIsZero(dcm) message:"CPDecimalMakeWithString(0) and CPDecimalIsZero()"];
|
||||
dcm = CPDecimalMakeWithParts(0,0);
|
||||
[self assertTrue:CPDecimalIsZero(dcm) message:"CPDecimalMakeWithParts(0)"];
|
||||
dcm = CPDecimalMakeZero();
|
||||
[self assertTrue:CPDecimalIsZero(dcm) message:"CPDecimalMakeZero()"];
|
||||
}
|
||||
|
||||
- (void)testOnes
|
||||
{
|
||||
var dcm = CPDecimalMakeOne();
|
||||
[self assertTrue:CPDecimalIsOne(dcm) message:"CPDecimalMakeOne() and CPDecimalIsOne()"];
|
||||
dcm = CPDecimalMakeWithString(@"1.00000e1");
|
||||
[self assertTrue:CPDecimalIsOne(dcm) message:"CPDecimalMakeWithString(1)"];
|
||||
dcm = CPDecimalMakeWithString(@"0.00100000e-3");
|
||||
[self assertTrue:CPDecimalIsOne(dcm) message:"CPDecimalMakeWithString(1)"];
|
||||
[self assert:1 equals:dcm._mantissa[0] message:"CPDecimalMakeWithString(1)"];
|
||||
}
|
||||
|
||||
- (void)testNormalize
|
||||
{
|
||||
dcm1 = CPDecimalMakeWithString( @"200" );
|
||||
dcm2 = CPDecimalMakeWithString( @"2" );
|
||||
[self assert:0 equals:CPDecimalNormalize(dcm1,dcm2,CPRoundDown) message:"CPDecimalNormalise() Tn1:call" ];
|
||||
[self assert:[2,0,0] equals:dcm1._mantissa message:"CPDecimalNormalise() Tn1: mantissa"];
|
||||
[self assert:0 equals:dcm1._exponent message:"CPDecimalNormalise() Tn1: exponent"];
|
||||
[self assert:[2] equals:dcm2._mantissa message:"CPDecimalNormalise() Tn1: mantissa"];
|
||||
[self assert:0 equals:dcm2._exponent message:"CPDecimalNormalise() Tn1: exponent"];
|
||||
|
||||
dcm1 = CPDecimalMakeWithString( @"0.001" );
|
||||
dcm2 = CPDecimalMakeWithString( @"123" );
|
||||
[self assert:0 equals:CPDecimalNormalize(dcm1,dcm2,CPRoundDown) message:"CPDecimalNormalise() Tn2:call" ];
|
||||
[self assert:[1] equals:dcm1._mantissa message:"CPDecimalNormalise() Tn2: mantissa"];
|
||||
[self assert:-3 equals:dcm1._exponent message:"CPDecimalNormalise() Tn2: exponent"];
|
||||
[self assert:[1,2,3,0,0,0] equals:dcm2._mantissa message:"CPDecimalNormalise() Tn2: mantissa"];
|
||||
[self assert:-3 equals:dcm2._exponent message:"CPDecimalNormalise() Tn2: exponent"];
|
||||
|
||||
dcm1 = CPDecimalMakeWithString( @"123" );
|
||||
dcm2 = CPDecimalMakeWithString( @"0.001" );
|
||||
[self assert:0 equals:CPDecimalNormalize(dcm1,dcm2,CPRoundDown) message:"CPDecimalNormalise() Tn3:call" ];
|
||||
[self assert:[1] equals:dcm2._mantissa message:"CPDecimalNormalise() Tn3: mantissa"];
|
||||
[self assert:-3 equals:dcm2._exponent message:"CPDecimalNormalise() Tn3: exponent"];
|
||||
[self assert:[1,2,3,0,0,0] equals:dcm1._mantissa message:"CPDecimalNormalise() Tn3: mantissa"];
|
||||
[self assert:-3 equals:dcm1._exponent message:"CPDecimalNormalise() Tn3: exponent"];
|
||||
|
||||
dcm1 = CPDecimalMakeWithString( @"-1e-7" );
|
||||
dcm2 = CPDecimalMakeWithString( @"-21e-8" );
|
||||
[self assert:0 equals:CPDecimalNormalize(dcm1,dcm2,CPRoundDown) message:"CPDecimalNormalise() Tn4:call" ];
|
||||
[self assert:[1,0] equals:dcm1._mantissa message:"CPDecimalNormalise() Tn4: mantissa"];
|
||||
[self assert:-8 equals:dcm1._exponent message:"CPDecimalNormalise() Tn4: exponent"];
|
||||
[self assert:[2,1] equals:dcm2._mantissa message:"CPDecimalNormalise() Tn4: mantissa"];
|
||||
[self assert:-8 equals:dcm2._exponent message:"CPDecimalNormalise() Tn4: exponent"];
|
||||
|
||||
// these will result in one number becoming zero.
|
||||
dcm1 = CPDecimalMakeWithString( @"1e0" );
|
||||
dcm2 = CPDecimalMakeWithString( @"10000000000000000000000000000000000001e2" );
|
||||
[self assert:CPCalculationLossOfPrecision equals:CPDecimalNormalize(dcm1,dcm2,CPRoundDown) message:"CPDecimalNormalise() Tnp1:call should ret LossOfPrecision" ];
|
||||
[self assert:[0] equals:dcm1._mantissa message:"CPDecimalNormalise() Tnp1: mantissa"];
|
||||
[self assert:0 equals:dcm1._exponent message:"CPDecimalNormalise() Tnp1: exponent"];
|
||||
[self assert:[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1] equals:dcm2._mantissa message:"CPDecimalNormalise() Tnp1: mantissa"];
|
||||
[self assert:2 equals:dcm2._exponent message:"CPDecimalNormalise() Tnp1: exponent"];
|
||||
|
||||
dcm1 = CPDecimalMakeWithString( @"10000000000000000000000000000000000001e2" );
|
||||
dcm2 = CPDecimalMakeWithString( @"1e0" );
|
||||
[self assert:CPCalculationLossOfPrecision equals:CPDecimalNormalize(dcm1,dcm2,CPRoundDown) message:"CPDecimalNormalise() Tnp2:call should ret LossOfPrecision" ];
|
||||
[self assert:[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1] equals:dcm1._mantissa message:"CPDecimalNormalise() Tnp2: mantissa"];
|
||||
[self assert:2 equals:dcm1._exponent message:"CPDecimalNormalise() Tnp2:exponent"];
|
||||
[self assert:[0] equals:dcm2._mantissa message:"CPDecimalNormalise() Tnp2: mantissa"];
|
||||
[self assert:0 equals:dcm2._exponent message:"CPDecimalNormalise() Tnp2: exponent"];
|
||||
|
||||
dcm1 = CPDecimalMakeWithString( @"10000000000000000000000000000000000001e127" );
|
||||
dcm2 = CPDecimalMakeWithString( @"1e0" );
|
||||
[self assert:CPCalculationLossOfPrecision equals:CPDecimalNormalize(dcm1,dcm2,CPRoundDown) message:"CPDecimalNormalise() Tnp3:call should ret LossOfPrecision" ];
|
||||
[self assert:[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1] equals:dcm1._mantissa message:"CPDecimalNormalise() Tnp3: mantissa"];
|
||||
[self assert:127 equals:dcm1._exponent message:"CPDecimalNormalise() Tnp3: exponent"];
|
||||
[self assert:[0] equals:dcm2._mantissa message:"CPDecimalNormalise() Tnp3: mantissa"];
|
||||
[self assert:0 equals:dcm2._exponent message:"CPDecimalNormalise() Tnp3: exponent"];
|
||||
|
||||
dcm1 = CPDecimalMakeWithString( @"1e-3" );
|
||||
dcm2 = CPDecimalMakeWithString( @"1e36" );
|
||||
[self assert:CPCalculationLossOfPrecision equals:CPDecimalNormalize(dcm1,dcm2,CPRoundDown) message:"CPDecimalNormalise() Tnp4:call should ret LossOfPrecision" ];
|
||||
[self assert:[0] equals:dcm1._mantissa message:"CPDecimalNormalise() Tnp4: mantissa"];
|
||||
[self assert:0 equals:dcm1._exponent message:"CPDecimalNormalise() Tnp4: exponent"];
|
||||
[self assert:[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] equals:dcm2._mantissa message:"CPDecimalNormalise() Tnp4: mantissa"];
|
||||
[self assert:-1 equals:dcm2._exponent message:"CPDecimalNormalise() Tnp4: exponent"];
|
||||
}
|
||||
|
||||
|
||||
- (void)testRound
|
||||
{
|
||||
var dcm = CPDecimalMakeWithString(@"0.00123");
|
||||
CPDecimalRound(dcm,dcm,3,CPRoundUp);
|
||||
[self assert:[2] equals:dcm._mantissa message:"CPDecimalRound() Tr1: mantissa"];
|
||||
[self assert:-3 equals:dcm._exponent message:"CPDecimalRound() Tr1: exponent"];
|
||||
|
||||
// plain
|
||||
var dcm1 = CPDecimalMakeZero();
|
||||
dcm = CPDecimalMakeWithString(@"123.456");
|
||||
CPDecimalRound(dcm1,dcm,0,CPRoundPlain);
|
||||
[self assert:[1,2,3] equals:dcm1._mantissa message:"CPDecimalRound() Tp1: mantissa"];
|
||||
[self assert:0 equals:dcm1._exponent message:"CPDecimalRound() Tp1: exponent"];
|
||||
|
||||
CPDecimalRound(dcm1,dcm,2,CPRoundPlain);
|
||||
[self assert:[1,2,3,4,6] equals:dcm1._mantissa message:"CPDecimalRound() Tp2: mantissa"];
|
||||
[self assert:-2 equals:dcm1._exponent message:"CPDecimalRound() Tp2: exponent"];
|
||||
|
||||
CPDecimalRound(dcm1,dcm,-2,CPRoundPlain);
|
||||
[self assert:[1] equals:dcm1._mantissa message:"CPDecimalRound() Tp3: mantissa"];
|
||||
[self assert:2 equals:dcm1._exponent message:"CPDecimalRound() Tp3: exponent"];
|
||||
|
||||
CPDecimalRound(dcm1,dcm,-4,CPRoundPlain);
|
||||
[self assert:[0] equals:dcm1._mantissa message:"CPDecimalRound() Tp4: mantissa"];
|
||||
[self assert:0 equals:dcm1._exponent message:"CPDecimalRound() Tp4: exponent"];
|
||||
|
||||
CPDecimalRound(dcm1,dcm,6,CPRoundPlain);
|
||||
[self assert:[1,2,3,4,5,6] equals:dcm1._mantissa message:"CPDecimalRound() Tp5: mantissa"];
|
||||
[self assert:-3 equals:dcm1._exponent message:"CPDecimalRound() Tp5: exponent"];
|
||||
|
||||
// down
|
||||
CPDecimalRound(dcm1,dcm,0,CPRoundDown);
|
||||
[self assert:[1,2,3] equals:dcm1._mantissa message:"CPDecimalRound() Td1: mantissa"];
|
||||
[self assert:0 equals:dcm1._exponent message:"CPDecimalRound() Td1: exponent"];
|
||||
|
||||
CPDecimalRound(dcm1,dcm,2,CPRoundDown);
|
||||
[self assert:[1,2,3,4,5] equals:dcm1._mantissa message:"CPDecimalRound() Td2: mantissa"];
|
||||
[self assert:-2 equals:dcm1._exponent message:"CPDecimalRound() Td2: exponent"];
|
||||
|
||||
CPDecimalRound(dcm1,dcm,-2,CPRoundDown);
|
||||
[self assert:[1] equals:dcm1._mantissa message:"CPDecimalRound() Td3: mantissa"];
|
||||
[self assert:2 equals:dcm1._exponent message:"CPDecimalRound() Td3: exponent"];
|
||||
|
||||
CPDecimalRound(dcm1,dcm,-4,CPRoundDown);
|
||||
[self assert:[0] equals:dcm1._mantissa message:"CPDecimalRound() Td4: mantissa"];
|
||||
[self assert:0 equals:dcm1._exponent message:"CPDecimalRound() Td4: exponent"];
|
||||
|
||||
CPDecimalRound(dcm1,dcm,6,CPRoundDown);
|
||||
[self assert:[1,2,3,4,5,6] equals:dcm1._mantissa message:"CPDecimalRound() Td5: mantissa"];
|
||||
[self assert:-3 equals:dcm1._exponent message:"CPDecimalRound() Td5: exponent"];
|
||||
|
||||
// up
|
||||
CPDecimalRound(dcm1,dcm,0,CPRoundUp);
|
||||
[self assert:[1,2,4] equals:dcm1._mantissa message:"CPDecimalRound() Tu1: mantissa"];
|
||||
[self assert:0 equals:dcm1._exponent message:"CPDecimalRound() Tu1: exponent"];
|
||||
|
||||
CPDecimalRound(dcm1,dcm,2,CPRoundUp);
|
||||
[self assert:[1,2,3,4,6] equals:dcm1._mantissa message:"CPDecimalRound() Tu2: mantissa"];
|
||||
[self assert:-2 equals:dcm1._exponent message:"CPDecimalRound() Tu2: exponent"];
|
||||
|
||||
CPDecimalRound(dcm1,dcm,-2,CPRoundUp);
|
||||
[self assert:[2] equals:dcm1._mantissa message:"CPDecimalRound() Tu3: mantissa"];
|
||||
[self assert:2 equals:dcm1._exponent message:"CPDecimalRound() Tu3: exponent"];
|
||||
|
||||
CPDecimalRound(dcm1,dcm,-4,CPRoundUp);
|
||||
[self assert:[0] equals:dcm1._mantissa message:"CPDecimalRound() Tu4: mantissa"];
|
||||
[self assert:0 equals:dcm1._exponent message:"CPDecimalRound() Tu4: exponent"];
|
||||
|
||||
CPDecimalRound(dcm1,dcm,6,CPRoundUp);
|
||||
[self assert:[1,2,3,4,5,6] equals:dcm1._mantissa message:"CPDecimalRound() Tu5: mantissa"];
|
||||
[self assert:-3 equals:dcm1._exponent message:"CPDecimalRound() Tu5: exponent"];
|
||||
|
||||
// bankers
|
||||
CPDecimalRound(dcm1,dcm,0,CPRoundBankers);
|
||||
[self assert:[1,2,3] equals:dcm1._mantissa message:"CPDecimalRound() Tb1: mantissa"];
|
||||
[self assert:0 equals:dcm1._exponent message:"CPDecimalRound() Tb1: exponent"];
|
||||
|
||||
CPDecimalRound(dcm1,dcm,2,CPRoundBankers);
|
||||
[self assert:[1,2,3,4,6] equals:dcm1._mantissa message:"CPDecimalRound() Tb2: mantissa"];
|
||||
[self assert:-2 equals:dcm1._exponent message:"CPDecimalRound() Tb2: exponent"];
|
||||
|
||||
CPDecimalRound(dcm1,dcm,-2,CPRoundBankers);
|
||||
[self assert:[1] equals:dcm1._mantissa message:"CPDecimalRound() Tb3: mantissa"];
|
||||
[self assert:2 equals:dcm1._exponent message:"CPDecimalRound() Tb3: exponent"];
|
||||
|
||||
CPDecimalRound(dcm1,dcm,-4,CPRoundBankers);
|
||||
[self assert:[0] equals:dcm1._mantissa message:"CPDecimalRound() Tb4: mantissa"];
|
||||
[self assert:0 equals:dcm1._exponent message:"CPDecimalRound() Tb4: exponent"];
|
||||
|
||||
CPDecimalRound(dcm1,dcm,6,CPRoundBankers);
|
||||
[self assert:[1,2,3,4,5,6] equals:dcm1._mantissa message:"CPDecimalRound() Tb5: mantissa"];
|
||||
[self assert:-3 equals:dcm1._exponent message:"CPDecimalRound() Tb5: exponent"];
|
||||
|
||||
// Noscale
|
||||
CPDecimalRound(dcm1,dcm,CPDecimalNoScale,CPRoundPlain);
|
||||
[self assert:[1,2,3,4,5,6] equals:dcm1._mantissa message:"CPDecimalRound() Tns1: mantissa"];
|
||||
[self assert:-3 equals:dcm1._exponent message:"CPDecimalRound() Tns1: exponent"];
|
||||
}
|
||||
|
||||
- (void)testCompare
|
||||
{
|
||||
var dcm1 = CPDecimalMakeWithString(@"75836");
|
||||
var dcm = CPDecimalMakeWithString(@"75836");
|
||||
var c = CPDecimalCompare(dcm1,dcm);
|
||||
[self assert:CPOrderedSame equals:c message:"CPDecimalCompare() Tc1: should be same"];
|
||||
|
||||
dcm1 = CPDecimalMakeWithString(@"75836");
|
||||
dcm = CPDecimalMakeWithString(@"75836e-9");
|
||||
c = CPDecimalCompare(dcm1,dcm);
|
||||
[self assert:CPOrderedDescending equals:c message:"CPDecimalCompare() Tc2: should be descending"];
|
||||
|
||||
dcm1 = CPDecimalMakeWithString(@"823479");
|
||||
dcm = CPDecimalMakeWithString(@"7082371231252");
|
||||
c = CPDecimalCompare(dcm1,dcm);
|
||||
[self assert:CPOrderedAscending equals:c message:"CPDecimalCompare() Tc3: should be descending"];
|
||||
|
||||
dcm1 = CPDecimalMakeWithString(@"0.00000000002");
|
||||
dcm = CPDecimalMakeWithString(@"-1e-9");
|
||||
c = CPDecimalCompare(dcm1,dcm);
|
||||
[self assert:CPOrderedDescending equals:c message:"CPDecimalCompare() Tc4: should be descending"];
|
||||
|
||||
dcm1 = CPDecimalMakeWithString(@"-23412345123e12");
|
||||
dcm = CPDecimalMakeWithString(@"-1e100");
|
||||
c = CPDecimalCompare(dcm1,dcm);
|
||||
[self assert:CPOrderedDescending equals:c message:"CPDecimalCompare() Tc4: should be descending"];
|
||||
}
|
||||
|
||||
- (void)testCompact
|
||||
{
|
||||
var dcm = CPDecimalMakeZero();
|
||||
dcm._mantissa = [0,0,0,0,1,0,0,0,0,1];
|
||||
dcm._exponent = 2;
|
||||
CPDecimalCompact(dcm);
|
||||
[self assert:2 equals:dcm._exponent message:"CPDecimalCompact() Tcm1: exponent"];
|
||||
[self assert:[1,0,0,0,0,1] equals:dcm._mantissa message:"CPDecimalCompact() Tcm1: mantissa"];
|
||||
|
||||
dcm = CPDecimalMakeZero();
|
||||
dcm._mantissa = [0,0,0,0,1,2,0,0,0,0];
|
||||
dcm._exponent = -4;
|
||||
dcm._isNegative = YES;
|
||||
CPDecimalCompact(dcm);
|
||||
[self assert:0 equals:dcm._exponent message:"CPDecimalCompact() Tcm2: exponent"];
|
||||
[self assert:[1,2] equals:dcm._mantissa message:"CPDecimalCompact() Tcm2: mantissa"];
|
||||
[self assert:YES equals:dcm._isNegative message:"CPDecimalCompact() Tcm2: sign"];
|
||||
|
||||
dcm = CPDecimalMakeZero();
|
||||
dcm._mantissa = [1,2,0,0,0,0];
|
||||
dcm._exponent = -1;
|
||||
CPDecimalCompact(dcm);
|
||||
[self assert:3 equals:dcm._exponent message:"CPDecimalCompact() Tcm3: exponent"];
|
||||
[self assert:[1,2] equals:dcm._mantissa message:"CPDecimalCompact() Tcm3: mantissa"];
|
||||
[self assert:NO equals:dcm._isNegative message:"CPDecimalCompact() Tcm3: sign"];
|
||||
[self assert:NO equals:dcm._isNaN message:"CPDecimalCompact() Tcm3: NaN is incorrectly set"];
|
||||
|
||||
dcm = CPDecimalMakeZero();
|
||||
dcm._mantissa = [8,9,0,0,0,0,1,2,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
|
||||
dcm._exponent = -20;
|
||||
dcm._isNegative = YES;
|
||||
CPDecimalCompact(dcm);
|
||||
[self assert:-5 equals:dcm._exponent message:"CPDecimalCompact() Tcm4: exponent"];
|
||||
[self assert:[8,9,0,0,0,0,1,2,3] equals:dcm._mantissa message:"CPDecimalCompact() Tcm4: mantissa"];
|
||||
[self assert:YES equals:dcm._isNegative message:"CPDecimalCompact() Tcm4: sign"];
|
||||
[self assert:NO equals:dcm._isNaN message:"CPDecimalCompact() Tcm4: NaN is incorrectly set"];
|
||||
}
|
||||
|
||||
- (void)testAdd
|
||||
{
|
||||
// test addition of positives
|
||||
var d1 = CPDecimalMakeWithString(@"1"),
|
||||
d2 = CPDecimalMakeWithParts(1, 0),
|
||||
dcm = CPDecimalMakeZero(),
|
||||
i = 50;
|
||||
while (i--)
|
||||
[self assert:CPDecimalAdd(d1, d1, d2, CPRoundPlain) equals:CPCalculationNoError message:"CPDecimalAdd() Tap1: addition"];
|
||||
[self assert:0 equals:d1._exponent message:"CPDecimalAdd() Tap1: exponent"];
|
||||
[self assert:[5,1] equals:d1._mantissa message:"CPDecimalAdd() Tap1: mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"CPDecimalAdd() Tap1: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalAdd() Tap1: NaN is incorrectly set"];
|
||||
|
||||
// test addition with negatives
|
||||
d1 = CPDecimalMakeWithString(@"-1");
|
||||
d2 = CPDecimalMakeWithString(@"-1e-10");
|
||||
[self assert:CPCalculationNoError equals:CPDecimalAdd(d1, d1, d2, CPRoundPlain) message:"CPDecimalAdd() Tan1: addition of 2 negatives"];
|
||||
[self assert:-10 equals:d1._exponent message:"CPDecimalAdd() Tan1: exponent"];
|
||||
[self assert:[1,0,0,0,0,0,0,0,0,0,1] equals:d1._mantissa message:"CPDecimalAdd() Tan1: mantissa"];
|
||||
[self assert:YES equals:d1._isNegative message:"CPDecimalAdd() Tan1: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalAdd() Tan1: NaN is incorrectly set"];
|
||||
|
||||
d1 = CPDecimalMakeWithString(@"-5");
|
||||
d2 = CPDecimalMakeWithString(@"11");
|
||||
[self assert:CPCalculationNoError equals:CPDecimalAdd(d1, d1, d2, CPRoundPlain) message:"CPDecimalAdd() Tan2: addition with negatives"];
|
||||
[self assert:0 equals:d1._exponent message:"CPDecimalAdd() Tan2: exponent"];
|
||||
[self assert:[6] equals:d1._mantissa message:"CPDecimalAdd() Tan2: mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"CPDecimalAdd() Tan2: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalAdd() Tan2: NaN is incorrectly set"];
|
||||
|
||||
d1 = CPDecimalMakeWithString(@"11");
|
||||
d2 = CPDecimalMakeWithString(@"-12");
|
||||
[self assert:CPCalculationNoError equals:CPDecimalAdd(d1, d1, d2, CPRoundPlain) message:"CPDecimalAdd() Tan3: addition with negatives"];
|
||||
[self assert:0 equals:d1._exponent message:"CPDecimalAdd() Tan3: exponent"];
|
||||
[self assert:[1] equals:d1._mantissa message:"CPDecimalAdd() Tan3: mantissa"];
|
||||
[self assert:YES equals:d1._isNegative message:"CPDecimalAdd() Tan3: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalAdd() Tan3: NaN is incorrectly set"];
|
||||
|
||||
// FIXME: test mantissa overflow handling - is there a loss of precision?? not according to gnustep - check cocoa!!!! CPCalculationLossOfPrecision?
|
||||
d1 = CPDecimalMakeWithString(@"12345");
|
||||
d2 = CPDecimalMakeWithString(@"99999999999999999999999999999999999999");
|
||||
[self assert:0 equals:CPDecimalAdd(d1, d1, d2, CPRoundPlain) message:"CPDecimalAdd() Tapc1: addition with mantissa overflow and rounding"];
|
||||
[self assert:1 equals:d1._exponent message:"CPDecimalAdd() Tapc1: exponent"];
|
||||
[self assert:[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4] equals:d1._mantissa message:"CPDecimalAdd() Tapc1: mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"CPDecimalAdd() Tapc1: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalAdd() Tapc1: NaN is incorrectly set"];
|
||||
|
||||
d1 = CPDecimalMakeWithString(@"1e127");
|
||||
d2 = CPDecimalMakeWithString(@"99999999999999999999999999999999999999");
|
||||
[self assert:CPDecimalAdd(d1, d1, d2, CPRoundPlain) equals:CPCalculationLossOfPrecision message:"CPDecimalAdd() Tapc2: addition loss of precision"];
|
||||
|
||||
// Overflow
|
||||
d1 = CPDecimalMakeWithString(@"1e127");
|
||||
d2 = CPDecimalMakeWithString(@"99999999999999999999999999999999999999e127");
|
||||
[self assert:CPDecimalAdd(d1, d1, d2, CPRoundPlain) equals:CPCalculationOverflow message:"CPDecimalAdd() Tao1: addition loss of precision"];
|
||||
}
|
||||
|
||||
- (void)testSubtract
|
||||
{
|
||||
var d1 = CPDecimalMakeZero();
|
||||
var d2 = CPDecimalMakeWithString(@"0.875");
|
||||
var d3 = CPDecimalMakeWithString(@"12.67");
|
||||
[self assert:CPCalculationNoError equals:CPDecimalSubtract(d1,d2,d3,CPRoundPlain) message:"CPDecimalSubtract(): Ts1: Should succeed"];
|
||||
[self assert:-3 equals:d1._exponent message:"CPDecimalSubtract(): Ts1: exponent"];
|
||||
[self assert:[1,1,7,9,5] equals:d1._mantissa message:"CPDecimalSubtract(): Ts1: mantissa"];
|
||||
[self assert:YES equals:d1._isNegative message:"CPDecimalSubtract(): Ts1: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalSubtract(): Ts1: NaN is incorrectly set"];
|
||||
|
||||
d1 = CPDecimalMakeZero();
|
||||
d2 = CPDecimalMakeWithString(@"-0.875");
|
||||
d3 = CPDecimalMakeWithString(@"-12.67");
|
||||
[self assert:CPCalculationNoError equals:CPDecimalSubtract(d1,d2,d3,CPRoundPlain) message:"CPDecimalSubtract(): Ts2: Should succeed"];
|
||||
[self assert:-3 equals:d1._exponent message:"CPDecimalSubtract(): Ts2: exponent"];
|
||||
[self assert:[1,1,7,9,5] equals:d1._mantissa message:"CPDecimalSubtract(): Ts2: mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"CPDecimalSubtract(): Ts2: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalSubtract(): Ts2: NaN is incorrectly set"];
|
||||
|
||||
d1 = CPDecimalMakeZero();
|
||||
d2 = CPDecimalMakeWithString(@"-0.875");
|
||||
d3 = CPDecimalMakeWithString(@"12.67e2");
|
||||
[self assert:CPCalculationNoError equals:CPDecimalSubtract(d1,d2,d3,CPRoundPlain) message:"CPDecimalSubtract(): Ts3: Should succeed"];
|
||||
[self assert:-3 equals:d1._exponent message:"CPDecimalSubtract(): Ts3: exponent"];
|
||||
[self assert:[1,2,6,7,8,7,5] equals:d1._mantissa message:"CPDecimalSubtract(): Ts3: mantissa"];
|
||||
[self assert:YES equals:d1._isNegative message:"CPDecimalSubtract(): Ts3: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalSubtract(): Ts3: NaN is incorrectly set"];
|
||||
|
||||
d1 = CPDecimalMakeZero();
|
||||
d2 = CPDecimalMakeWithString(@"0.875");
|
||||
d3 = CPDecimalMakeWithString(@"-12.67");
|
||||
[self assert:CPCalculationNoError equals:CPDecimalSubtract(d1,d2,d3,CPRoundPlain) message:"CPDecimalSubtract(): Ts4: Should succeed"];
|
||||
[self assert:-3 equals:d1._exponent message:"CPDecimalSubtract(): Ts4: exponent"];
|
||||
[self assert:[1,3,5,4,5] equals:d1._mantissa message:"CPDecimalSubtract(): Ts4: mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"CPDecimalSubtract(): Ts4: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalSubtract(): Ts4: NaN is incorrectly set"];
|
||||
|
||||
// loss of precision
|
||||
d1 = CPDecimalMakeZero();
|
||||
d2 = CPDecimalMakeWithString(@"1e-128");
|
||||
d3 = CPDecimalMakeWithString(@"1");
|
||||
[self assert:CPCalculationLossOfPrecision equals:CPDecimalSubtract(d1,d2,d3,CPRoundPlain) message:"CPDecimalSubtract(): Tsp1: Should throw loss of precision"];
|
||||
[self assert:0 equals:d1._exponent message:"CPDecimalSubtract(): Tsp1: exponent"];
|
||||
[self assert:[1] equals:d1._mantissa message:"CPDecimalSubtract(): Tsp1: mantissa"];
|
||||
[self assert:YES equals:d1._isNegative message:"CPDecimalSubtract(): Tsp1: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalSubtract(): Tsp1: NaN is incorrectly set"];
|
||||
}
|
||||
|
||||
- (void)testDivide
|
||||
{
|
||||
var d1 = CPDecimalMakeZero();
|
||||
var d2 = CPDecimalMakeWithString(@"55e12");
|
||||
var d3 = CPDecimalMakeWithString(@"-5e20");
|
||||
[self assert:CPCalculationNoError equals:CPDecimalDivide(d1,d2,d3,CPRoundPlain) message:"CPDecimalDivide(): Td1: Should succeed"];
|
||||
[self assert:-8 equals:d1._exponent message:"CPDecimalDivide(): Td1: exponent"];
|
||||
[self assert:[1,1] equals:d1._mantissa message:"CPDecimalDivide(): Td1: mantissa"];
|
||||
[self assert:YES equals:d1._isNegative message:"CPDecimalDivide(): Td1: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalDivide(): Td1: NaN is incorrectly set"];
|
||||
|
||||
d1 = CPDecimalMakeZero();
|
||||
d2 = CPDecimalMakeWithString(@"-1e12");
|
||||
d3 = CPDecimalMakeWithString(@"-1e6");
|
||||
[self assert:CPCalculationNoError equals:CPDecimalDivide(d1,d2,d3,CPRoundPlain) message:"CPDecimalDivide(): Td2: Should succeed"];
|
||||
[self assert:6 equals:d1._exponent message:"CPDecimalDivide(): Td2: exponent"];
|
||||
[self assert:[1] equals:d1._mantissa message:"CPDecimalDivide(): Td2: mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"CPDecimalDivide(): Td2: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalDivide(): Td2: NaN is incorrectly set"];
|
||||
|
||||
d1 = CPDecimalMakeZero();
|
||||
d2 = CPDecimalMakeWithString(@"1");
|
||||
d3 = CPDecimalMakeWithString(@"0.00001");
|
||||
[self assert:CPCalculationNoError equals:CPDecimalDivide(d1,d2,d3,CPRoundPlain) message:"CPDecimalDivide(): Td3: Should succeed"];
|
||||
[self assert:5 equals:d1._exponent message:"CPDecimalDivide(): Td3: exponent"];
|
||||
[self assert:[1] equals:d1._mantissa message:"CPDecimalDivide(): Td3: mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"CPDecimalDivide(): Td3: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalDivide(): Td3: NaN is incorrectly set"];
|
||||
|
||||
d1 = CPDecimalMakeZero();
|
||||
d2 = CPDecimalMakeWithString(@"1");
|
||||
d3 = CPDecimalMakeWithString(@"3");
|
||||
[self assert:CPCalculationLossOfPrecision equals:CPDecimalDivide(d1,d2,d3,CPRoundPlain) message:"CPDecimalDivide(): Tdp1: Should Loss of precision"];
|
||||
[self assert:-38 equals:d1._exponent message:"CPDecimalDivide(): Tdp1: exponent"];
|
||||
[self assert:[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3] equals:d1._mantissa message:"CPDecimalDivide(): Tdp1: mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"CPDecimalDivide(): Tdp1: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalDivide(): Tdp1: NaN is incorrectly set"];
|
||||
|
||||
// Why doesnt Cocoa round the final digit up?
|
||||
d1 = CPDecimalMakeZero();
|
||||
d2 = CPDecimalMakeWithString(@"-0.875");
|
||||
d3 = CPDecimalMakeWithString(@"12");
|
||||
[self assert:CPCalculationLossOfPrecision equals:CPDecimalDivide(d1,d2,d3,CPRoundUp) message:"CPDecimalDivide(): Tdp2: Should Loss of precision"];
|
||||
[self assert:-39 equals:d1._exponent message:"CPDecimalDivide(): Td2: exponent"];
|
||||
[self assert:[7,2,9,1,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6] equals:d1._mantissa message:"CPDecimalDivide(): Td2: mantissa"];
|
||||
[self assert:YES equals:d1._isNegative message:"CPDecimalDivide(): Td2: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalDivide(): Td2: NaN is incorrectly set"];
|
||||
|
||||
// div zero
|
||||
d1 = CPDecimalMakeZero();
|
||||
d2 = CPDecimalMakeWithString(@"-0.875");
|
||||
d3 = CPDecimalMakeWithString(@"0");
|
||||
[self assert:CPCalculationDivideByZero equals:CPDecimalDivide(d1,d2,d3,CPRoundUp) message:"CPDecimalDivide(): Tdp2: Should Loss of precision"];
|
||||
}
|
||||
|
||||
- (void)testMultiply
|
||||
{
|
||||
var d1 = CPDecimalMakeZero();
|
||||
var d2 = CPDecimalMakeWithString(@"12");
|
||||
var d3 = CPDecimalMakeWithString(@"-1441231251321235231");
|
||||
[self assert:CPCalculationNoError equals:CPDecimalMultiply(d1,d2,d3,CPRoundPlain) message:"CPDecimalMultiply(): Tm1: Should succeed"];
|
||||
[self assert:0 equals:d1._exponent message:"CPDecimalMultiply(): Tm1: exponent"];
|
||||
[self assert:[1,7,2,9,4,7,7,5,0,1,5,8,5,4,8,2,2,7,7,2] equals:d1._mantissa message:"CPDecimalMultiply(): Tm1: mantissa"];
|
||||
[self assert:YES equals:d1._isNegative message:"CPDecimalMultiply(): Tm1: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalMultiply(): Tm1: NaN is incorrectly set"];
|
||||
|
||||
d1 = CPDecimalMakeZero();
|
||||
d2 = CPDecimalMakeWithString(@"23e100");
|
||||
d3 = CPDecimalMakeWithString(@"-13e-76");
|
||||
[self assert:CPCalculationNoError equals:CPDecimalMultiply(d1,d2,d3,CPRoundPlain) message:"CPDecimalMultiply(): Tm2: Should succeed"];
|
||||
[self assert:24 equals:d1._exponent message:"CPDecimalMultiply(): Tm2: exponent"];
|
||||
[self assert:[2,9,9] equals:d1._mantissa message:"CPDecimalMultiply(): Tm2: mantissa"];
|
||||
[self assert:YES equals:d1._isNegative message:"CPDecimalMultiply(): Tm2: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalMultiply(): Tm2: NaN is incorrectly set"];
|
||||
|
||||
d1 = CPDecimalMakeZero();
|
||||
d2 = CPDecimalMakeWithString(@"-0.8888");
|
||||
d3 = CPDecimalMakeWithString(@"8.88e2");
|
||||
[self assert:CPCalculationNoError equals:CPDecimalMultiply(d1,d2,d3,CPRoundPlain) message:"CPDecimalMultiply(): Tm3: Should succeed"];
|
||||
[self assert:-4 equals:d1._exponent message:"CPDecimalMultiply(): Tm3: exponent"];
|
||||
[self assert:[7,8,9,2,5,4,4] equals:d1._mantissa message:"CPDecimalMultiply(): Tm3: mantissa"];
|
||||
[self assert:YES equals:d1._isNegative message:"CPDecimalMultiply(): Tm3: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalMultiply(): Tm3: NaN is incorrectly set"];
|
||||
|
||||
d1 = CPDecimalMakeZero();
|
||||
d2 = CPDecimalMakeWithString(@"-1e111");
|
||||
d3 = CPDecimalMakeWithString(@"-1e-120");
|
||||
[self assert:CPCalculationNoError equals:CPDecimalMultiply(d1,d2,d3,CPRoundPlain) message:"CPDecimalMultiply(): Tm4: Should succeed"];
|
||||
[self assert:-9 equals:d1._exponent message:"CPDecimalMultiply(): Tm4: exponent"];
|
||||
[self assert:[1] equals:d1._mantissa message:"CPDecimalMultiply(): Tm4: mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"CPDecimalMultiply(): Tm4: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalMultiply(): Tm4: NaN is incorrectly set"];
|
||||
|
||||
// loss of precision
|
||||
d1 = CPDecimalMakeZero();
|
||||
d2 = CPDecimalMakeWithString(@"212341251123892374823742638472481124");
|
||||
d3 = CPDecimalMakeWithString(@"127889465810478913");
|
||||
[self assert:CPCalculationLossOfPrecision equals:CPDecimalMultiply(d1,d2,d3,CPRoundDown) message:"CPDecimalMultiply(): Tmp1: Should throw loss of precision"];
|
||||
[self assert:15 equals:d1._exponent message:"CPDecimalMultiply(): Tmp1: exponent"]; // 69 diff
|
||||
[self assert:[2,7,1,5,6,2,0,9,1,7,5,7,6,3,3,5,0,9,2,9,7,4,0,2,3,5,6,0,8,0,6,9,5,2,8,3,9,1] equals:d1._mantissa message:"CPDecimalMultiply(): Tmp1: mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"CPDecimalMultiply(): Tmp1: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalMultiply(): Tmp1: NaN is incorrectly set"];
|
||||
|
||||
// overflow
|
||||
d1 = CPDecimalMakeZero();
|
||||
d2 = CPDecimalMakeWithString(@"1e110");
|
||||
d3 = CPDecimalMakeWithString(@"1e111");
|
||||
[self assert:CPCalculationOverflow equals:CPDecimalMultiply(d1,d2,d3,CPRoundDown) message:"CPDecimalMultiply(): Tmo1: Should throw overflow"];
|
||||
[self assert:YES equals:d1._isNaN message:"CPDecimalMultiply(): Tmo1: NaN is incorrectly set"];
|
||||
}
|
||||
|
||||
// Power is unsigned
|
||||
- (void)testPower
|
||||
{
|
||||
var d1 = CPDecimalMakeZero();
|
||||
var d2 = CPDecimalMakeWithString(@"123");
|
||||
var d3 = 12;
|
||||
[self assert:CPCalculationNoError equals:CPDecimalPower(d1,d2,d3,CPRoundPlain) message:"CPDecimalPower(): Tp1: Should succeed"];
|
||||
[self assert:0 equals:d1._exponent message:"CPDecimalPower(): Tp1: exponent"];
|
||||
[self assert:[1,1,9,9,1,1,6,3,8,4,8,7,1,6,9,0,6,2,9,7,0,7,2,7,2,1] equals:d1._mantissa message:"CPDecimalPower(): Tp1: mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"CPDecimalPower(): Tp1: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalPower(): Tp1: NaN is incorrectly set"];
|
||||
|
||||
//0.00000 13893554059925661274821814636807535200 1 cocoa (39 digits)
|
||||
//0.00000 13893554059925661274821814636807535204 This , a few off
|
||||
d1 = CPDecimalMakeZero();
|
||||
d2 = CPDecimalMakeWithString(@"0.875");
|
||||
d3 = 101;
|
||||
[self assert:CPCalculationLossOfPrecision equals:CPDecimalPower(d1,d2,d3,CPRoundUp) message:"CPDecimalPower(): Tp2: Should throw Loss of precision"];
|
||||
[self assert:-43 equals:d1._exponent message:"CPDecimalPower(): Tp2: exponent"];
|
||||
[self assert:[1,3,8,9,3,5,5,4,0,5,9,9,2,5,6,6,1,2,7,4,8,2,1,8,1,4,6,3,6,8,0,7,5,3,5,2,0,4] equals:d1._mantissa message:"CPDecimalPower(): Tp2: mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"CPDecimalPower(): Tp2: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalPower(): Tp2: NaN is incorrectly set"];
|
||||
|
||||
}
|
||||
|
||||
- (void)testPower10
|
||||
{
|
||||
var d1 = CPDecimalMakeZero();
|
||||
var d2 = CPDecimalMakeWithString(@"-0.875");
|
||||
var d3 = 3;
|
||||
[self assert:CPCalculationNoError equals:CPDecimalMultiplyByPowerOf10(d1,d2,d3,CPRoundPlain) message:"CPDecimalMultiplyByPowerOf10(): Tpp1: Should succeed"];
|
||||
[self assert:0 equals:d1._exponent message:"CPDecimalMultiplyByPowerOf10(): Tpp1: exponent"];
|
||||
[self assert:[8,7,5] equals:d1._mantissa message:"CPDecimalMultiplyByPowerOf10(): Tpp1: mantissa"];
|
||||
[self assert:YES equals:d1._isNegative message:"CPDecimalMultiplyByPowerOf10(): Tpp1: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalMultiplyByPowerOf10(): Tpp1: NaN is incorrectly set"];
|
||||
|
||||
d1 = CPDecimalMakeZero();
|
||||
d2 = CPDecimalMakeWithString(@"1e-120");
|
||||
d3 = 130;
|
||||
[self assert:CPCalculationNoError equals:CPDecimalMultiplyByPowerOf10(d1,d2,d3,CPRoundPlain) message:"CPDecimalMultiplyByPowerOf10(): Tpp2: Should succeed"];
|
||||
[self assert:10 equals:d1._exponent message:"CPDecimalMultiplyByPowerOf10(): Tpp2: exponent"];
|
||||
[self assert:[1] equals:d1._mantissa message:"CPDecimalMultiplyByPowerOf10(): Tpp2: mantissa"];
|
||||
[self assert:NO equals:d1._isNegative message:"CPDecimalMultiplyByPowerOf10(): Tpp2: sign"];
|
||||
[self assert:NO equals:d1._isNaN message:"CPDecimalMultiplyByPowerOf10(): Tpp2: NaN is incorrectly set"];
|
||||
}
|
||||
|
||||
- (void)testString
|
||||
{
|
||||
var dcm = CPDecimalMakeWithString(@"0.00123");
|
||||
[self assert:"0.00123" equals:CPDecimalString(dcm,nil) message:"CPDecimalString() Ts1"];
|
||||
dcm = CPDecimalMakeWithString(@"2e3");
|
||||
[self assert:"2000" equals:CPDecimalString(dcm,nil) message:"CPDecimalString() Ts2"];
|
||||
dcm = CPDecimalMakeWithString(@"0.00876e-5");
|
||||
[self assert:"0.0000000876" equals:CPDecimalString(dcm,nil) message:"CPDecimalString() Ts3"];
|
||||
dcm = CPDecimalMakeWithString(@"98.56e10");
|
||||
[self assert:"985600000000" equals:CPDecimalString(dcm,nil) message:"CPDecimalString() Ts4"];
|
||||
dcm = CPDecimalMakeWithString(@"-1e-1");
|
||||
[self assert:"-0.1" equals:CPDecimalString(dcm,nil) message:"CPDecimalString() Ts5"];
|
||||
dcm = CPDecimalMakeWithString(@"-5e20");
|
||||
[self assert:"-500000000000000000000" equals:CPDecimalString(dcm,nil) message:"CPDecimalString() Ts6"];
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in new issue
Block a user