mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-30 16:30:41 +00:00
Use the NSDecimal functions for this class
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@6904 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
624b81baf8
commit
f15996266d
1 changed files with 496 additions and 0 deletions
496
Source/NSDecimalNumber.m
Normal file
496
Source/NSDecimalNumber.m
Normal file
|
@ -0,0 +1,496 @@
|
|||
/*
|
||||
NSDecimalNumber class
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Fred Kiefer <FredKiefer@gmx.de>
|
||||
Created: July 2000
|
||||
|
||||
This file is part of the GNUstep Base Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
*/
|
||||
|
||||
#include <Foundation/NSException.h>
|
||||
#include <Foundation/NSDecimal.h>
|
||||
#include <Foundation/NSDecimalNumber.h>
|
||||
#include <Foundation/NSUserDefaults.h>
|
||||
|
||||
static NSDecimalNumberHandler *handler;
|
||||
|
||||
@implementation NSDecimalNumberHandler
|
||||
|
||||
+ (id)defaultDecimalNumberHandler
|
||||
{
|
||||
if (handler == nil)
|
||||
handler = [[self alloc] initWithRoundingMode: NSRoundPlain
|
||||
scale: 38
|
||||
raiseOnExactness: NO
|
||||
raiseOnOverflow: YES
|
||||
raiseOnUnderflow: YES
|
||||
raiseOnDivideByZero: YES];
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
+ (id)decimalNumberHandlerWithRoundingMode:(NSRoundingMode)roundingMode
|
||||
scale:(short)scale
|
||||
raiseOnExactness:(BOOL)raiseOnExactness
|
||||
raiseOnOverflow:(BOOL)raiseOnOverflow
|
||||
raiseOnUnderflow:(BOOL)raiseOnUnderflow
|
||||
raiseOnDivideByZero:(BOOL)raiseOnDivideByZero
|
||||
{
|
||||
return AUTORELEASE([[self alloc] initWithRoundingMode: roundingMode
|
||||
scale: scale
|
||||
raiseOnExactness: raiseOnExactness
|
||||
raiseOnOverflow: raiseOnOverflow
|
||||
raiseOnUnderflow: raiseOnUnderflow
|
||||
raiseOnDivideByZero: raiseOnDivideByZero]);
|
||||
}
|
||||
|
||||
- (id)initWithRoundingMode:(NSRoundingMode)roundingMode
|
||||
scale:(short)scale
|
||||
raiseOnExactness:(BOOL)raiseOnExactness
|
||||
raiseOnOverflow:(BOOL)raiseOnOverflow
|
||||
raiseOnUnderflow:(BOOL)raiseOnUnderflow
|
||||
raiseOnDivideByZero:(BOOL)raiseOnDivideByZero
|
||||
{
|
||||
_roundingMode = roundingMode;
|
||||
_scale = scale;
|
||||
_raiseOnExactness = raiseOnExactness;
|
||||
_raiseOnOverflow = raiseOnOverflow;
|
||||
_raiseOnUnderflow = raiseOnUnderflow;
|
||||
_raiseOnDivideByZero = raiseOnDivideByZero;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSDecimalNumber*) exceptionDuringOperation: (SEL)method
|
||||
error: (NSCalculationError)error
|
||||
leftOperand: (NSDecimalNumber*)leftOperand
|
||||
rightOperand: (NSDecimalNumber*)rightOperand
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case NSCalculationNoError: return nil;
|
||||
case NSCalculationUnderflow:
|
||||
if (_raiseOnUnderflow)
|
||||
// FIXME: What exception to raise?
|
||||
[NSException raise: @"NSDecimalNumberException" format: @"Underflow"];
|
||||
else
|
||||
return [NSDecimalNumber minimumDecimalNumber];
|
||||
break;
|
||||
case NSCalculationOverflow:
|
||||
if (_raiseOnOverflow)
|
||||
[NSException raise: @"NSDecimalNumberException" format: @"Overflow"];
|
||||
else
|
||||
return [NSDecimalNumber maximumDecimalNumber];
|
||||
break;
|
||||
case NSCalculationLossOfPrecision:
|
||||
if (_raiseOnExactness)
|
||||
[NSException raise: @"NSDecimalNumberException" format: @"Loss of precision"];
|
||||
else
|
||||
return nil;
|
||||
break;
|
||||
case NSCalculationDivideByZero:
|
||||
if (_raiseOnDivideByZero)
|
||||
[NSException raise: @"NSDecimalNumberException" format: @"Divide by zero"];
|
||||
else
|
||||
return [NSDecimalNumber notANumber];
|
||||
break;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSRoundingMode) roundingMode
|
||||
{
|
||||
return _roundingMode;
|
||||
}
|
||||
|
||||
- (short) scale
|
||||
{
|
||||
return _scale;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation NSDecimalNumber
|
||||
|
||||
static NSDecimalNumber *maxNumber;
|
||||
static NSDecimalNumber *minNumber;
|
||||
static NSDecimalNumber *notANumber;
|
||||
static NSDecimalNumber *zero;
|
||||
static NSDecimalNumber *one;
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
NSDecimal d;
|
||||
|
||||
d.validNumber = NO;
|
||||
notANumber = [[self alloc] initWithDecimal: d];
|
||||
NSDecimalMax(&d);
|
||||
maxNumber = [[self alloc] initWithDecimal: d];
|
||||
NSDecimalMin(&d);
|
||||
minNumber = [[self alloc] initWithDecimal: d];
|
||||
zero = [[self alloc] initWithMantissa: 0
|
||||
exponent: 0
|
||||
isNegative: NO];
|
||||
one = [[self alloc] initWithMantissa: 1
|
||||
exponent: 0
|
||||
isNegative: NO];
|
||||
}
|
||||
|
||||
+ (id <NSDecimalNumberBehaviors>)defaultBehavior
|
||||
{
|
||||
// Reuse the handler from the class NSDecimalNumberHandler
|
||||
return [NSDecimalNumberHandler defaultDecimalNumberHandler];
|
||||
}
|
||||
|
||||
+ (void)setDefaultBehavior:(id <NSDecimalNumberBehaviors>)behavior
|
||||
{
|
||||
// Reuse the handler from the class NSDecimalNumberHandler
|
||||
// Might give interessting result on this class as behavior may came
|
||||
// from a different class
|
||||
ASSIGN(handler, behavior);
|
||||
}
|
||||
|
||||
+ (NSDecimalNumber *)maximumDecimalNumber
|
||||
{
|
||||
return maxNumber;
|
||||
}
|
||||
+ (NSDecimalNumber *)minimumDecimalNumber
|
||||
{
|
||||
return minNumber;
|
||||
}
|
||||
|
||||
+ (NSDecimalNumber *)notANumber
|
||||
{
|
||||
return notANumber;
|
||||
}
|
||||
|
||||
+ (NSDecimalNumber *)zero
|
||||
{
|
||||
return zero;
|
||||
}
|
||||
|
||||
+ (NSDecimalNumber *)one
|
||||
{
|
||||
return one;
|
||||
}
|
||||
|
||||
+ (NSDecimalNumber *)decimalNumberWithDecimal:(NSDecimal)decimal
|
||||
{
|
||||
return AUTORELEASE([[self alloc] initWithDecimal: decimal]);
|
||||
}
|
||||
|
||||
+ (NSDecimalNumber *)decimalNumberWithMantissa:(unsigned long long)mantissa
|
||||
exponent:(short)exponent
|
||||
isNegative:(BOOL)isNegative
|
||||
{
|
||||
return AUTORELEASE([[self alloc] initWithMantissa: mantissa
|
||||
exponent: exponent
|
||||
isNegative: isNegative]);
|
||||
}
|
||||
|
||||
+ (NSDecimalNumber *)decimalNumberWithString:(NSString *)numericString
|
||||
{
|
||||
return AUTORELEASE([[self alloc] initWithString: numericString]);
|
||||
}
|
||||
|
||||
+ (NSDecimalNumber *)decimalNumberWithString:(NSString *)numericString
|
||||
locale:(NSDictionary *)locale
|
||||
{
|
||||
return AUTORELEASE([[self alloc] initWithString: numericString
|
||||
locale: locale]);
|
||||
}
|
||||
|
||||
|
||||
- (id)initWithDecimal:(NSDecimal)decimal
|
||||
{
|
||||
NSDecimalCopy(&data, &decimal);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithMantissa:(unsigned long long)mantissa
|
||||
exponent:(short)exponent
|
||||
isNegative:(BOOL)flag
|
||||
{
|
||||
NSDecimal decimal;
|
||||
|
||||
NSDecimalFromComponents(&decimal, mantissa, exponent, flag);
|
||||
return [self initWithDecimal: decimal];
|
||||
}
|
||||
|
||||
- (id)initWithString:(NSString *)numberValue
|
||||
{
|
||||
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
|
||||
|
||||
return [self initWithString: numberValue
|
||||
locale: [defs dictionaryRepresentation]];
|
||||
}
|
||||
|
||||
- (id)initWithString:(NSString *)numberValue
|
||||
locale:(NSDictionary *)locale;
|
||||
{
|
||||
NSDecimal decimal;
|
||||
|
||||
NSDecimalFromString(&decimal, numberValue, locale);
|
||||
return [self initWithDecimal: decimal];
|
||||
}
|
||||
|
||||
- (NSString *)descriptionWithLocale:(NSDictionary *)locale
|
||||
{
|
||||
return NSDecimalString(&data, locale);
|
||||
}
|
||||
|
||||
- (const char *)objCType
|
||||
{
|
||||
return "d";
|
||||
}
|
||||
|
||||
- (NSDecimal)decimalValue
|
||||
{
|
||||
NSDecimal decimal;
|
||||
|
||||
NSDecimalCopy(&decimal, &data);
|
||||
return decimal;
|
||||
}
|
||||
|
||||
- (double)doubleValue
|
||||
{
|
||||
return NSDecimalDouble(&data);
|
||||
}
|
||||
|
||||
- (NSComparisonResult)compare:(NSNumber *)decimalNumber
|
||||
{
|
||||
if ([decimalNumber isMemberOfClass: [self class]])
|
||||
{
|
||||
NSDecimal d1 = [self decimalValue];
|
||||
NSDecimal d2 = [(NSDecimalNumber*)decimalNumber decimalValue];
|
||||
|
||||
return NSDecimalCompare(&d1, &d2);
|
||||
}
|
||||
else
|
||||
return [super compare: decimalNumber];
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)decimalNumber
|
||||
{
|
||||
return [self decimalNumberByAdding: decimalNumber
|
||||
withBehavior: [isa defaultBehavior]];
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)decimalNumber
|
||||
withBehavior:(id<NSDecimalNumberBehaviors>)behavior
|
||||
{
|
||||
NSDecimal result;
|
||||
NSDecimal d1 = [self decimalValue];
|
||||
NSDecimal d2 = [decimalNumber decimalValue];
|
||||
NSCalculationError error;
|
||||
NSDecimalNumber *res;
|
||||
|
||||
error = NSDecimalAdd(&result, &d1, &d2, [behavior roundingMode]);
|
||||
if (error)
|
||||
{
|
||||
res = [behavior exceptionDuringOperation: _cmd
|
||||
error: error
|
||||
leftOperand: self
|
||||
rightOperand: decimalNumber];
|
||||
if (res != nil)
|
||||
return res;
|
||||
}
|
||||
|
||||
return [NSDecimalNumber decimalNumberWithDecimal: result];
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)decimalNumber
|
||||
{
|
||||
return [self decimalNumberBySubtracting: decimalNumber
|
||||
withBehavior: [isa defaultBehavior]];
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)decimalNumber
|
||||
withBehavior:(id <NSDecimalNumberBehaviors>)behavior
|
||||
{
|
||||
NSDecimal result;
|
||||
NSDecimal d1 = [self decimalValue];
|
||||
NSDecimal d2 = [decimalNumber decimalValue];
|
||||
NSCalculationError error;
|
||||
NSDecimalNumber *res;
|
||||
|
||||
error = NSDecimalSubtract(&result, &d1, &d2, [behavior roundingMode]);
|
||||
if (error)
|
||||
{
|
||||
res = [behavior exceptionDuringOperation: _cmd
|
||||
error: error
|
||||
leftOperand: self
|
||||
rightOperand: decimalNumber];
|
||||
if (res != nil)
|
||||
return res;
|
||||
}
|
||||
|
||||
return [NSDecimalNumber decimalNumberWithDecimal: result];
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)decimalNumber
|
||||
{
|
||||
return [self decimalNumberByMultiplyingBy: decimalNumber
|
||||
withBehavior: [isa defaultBehavior]];
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)decimalNumber
|
||||
withBehavior:(id <NSDecimalNumberBehaviors>)behavior
|
||||
{
|
||||
NSDecimal result;
|
||||
NSDecimal d1 = [self decimalValue];
|
||||
NSDecimal d2 = [decimalNumber decimalValue];
|
||||
NSCalculationError error;
|
||||
NSDecimalNumber *res;
|
||||
|
||||
error = NSDecimalMultiply(&result, &d1, &d2, [behavior roundingMode]);
|
||||
if (error)
|
||||
{
|
||||
res = [behavior exceptionDuringOperation: _cmd
|
||||
error: error
|
||||
leftOperand: self
|
||||
rightOperand: decimalNumber];
|
||||
if (res != nil)
|
||||
return res;
|
||||
}
|
||||
|
||||
return [NSDecimalNumber decimalNumberWithDecimal: result];
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)decimalNumber
|
||||
{
|
||||
return [self decimalNumberByDividingBy: decimalNumber
|
||||
withBehavior: [isa defaultBehavior]];
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)decimalNumber
|
||||
withBehavior:(id <NSDecimalNumberBehaviors>)behavior
|
||||
{
|
||||
NSDecimal result;
|
||||
NSDecimal d1 = [self decimalValue];
|
||||
NSDecimal d2 = [decimalNumber decimalValue];
|
||||
NSCalculationError error;
|
||||
NSDecimalNumber *res;
|
||||
|
||||
error = NSDecimalDivide(&result, &d1, &d2, [behavior roundingMode]);
|
||||
if (error)
|
||||
{
|
||||
res = [behavior exceptionDuringOperation: _cmd
|
||||
error: error
|
||||
leftOperand: self
|
||||
rightOperand: decimalNumber];
|
||||
if (res != nil)
|
||||
return res;
|
||||
}
|
||||
|
||||
return [NSDecimalNumber decimalNumberWithDecimal: result];
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)decimalNumberByMultiplyingByPowerOf10:(short)power
|
||||
{
|
||||
return [self decimalNumberByMultiplyingByPowerOf10: power
|
||||
withBehavior: [isa defaultBehavior]];
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)decimalNumberByMultiplyingByPowerOf10:(short)power
|
||||
withBehavior:(id <NSDecimalNumberBehaviors>)behavior
|
||||
{
|
||||
NSDecimal result;
|
||||
NSDecimal d1 = [self decimalValue];
|
||||
NSCalculationError error;
|
||||
NSDecimalNumber *res;
|
||||
|
||||
error = NSDecimalMultiplyByPowerOf10(&result, &d1,
|
||||
power, [behavior roundingMode]);
|
||||
if (error)
|
||||
{
|
||||
res = [behavior exceptionDuringOperation: _cmd
|
||||
error: error
|
||||
leftOperand: self
|
||||
rightOperand: nil];
|
||||
if (res != nil)
|
||||
return res;
|
||||
}
|
||||
|
||||
return [NSDecimalNumber decimalNumberWithDecimal: result];
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)decimalNumberByRaisingToPower:(unsigned)power
|
||||
{
|
||||
return [self decimalNumberByRaisingToPower: power
|
||||
withBehavior: [isa defaultBehavior]];
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)decimalNumberByRaisingToPower:(unsigned)power
|
||||
withBehavior:(id <NSDecimalNumberBehaviors>)behavior
|
||||
{
|
||||
NSDecimal result;
|
||||
NSDecimal d1 = [self decimalValue];
|
||||
NSCalculationError error;
|
||||
NSDecimalNumber *res;
|
||||
|
||||
error = NSDecimalPower(&result, &d1,
|
||||
power, [behavior roundingMode]);
|
||||
if (error)
|
||||
{
|
||||
res = [behavior exceptionDuringOperation: _cmd
|
||||
error: error
|
||||
leftOperand: self
|
||||
rightOperand: nil];
|
||||
if (res != nil)
|
||||
return res;
|
||||
}
|
||||
|
||||
return [NSDecimalNumber decimalNumberWithDecimal: result];
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)decimalNumberByRoundingAccordingToBehavior:(id <NSDecimalNumberBehaviors>)behavior
|
||||
{
|
||||
NSDecimal result;
|
||||
NSDecimal d1 = [self decimalValue];
|
||||
|
||||
NSDecimalRound(&result, &d1, [behavior scale], [behavior roundingMode]);
|
||||
return [NSDecimalNumber decimalNumberWithDecimal: result];
|
||||
}
|
||||
|
||||
|
||||
// Methods for NSDecimalNumberBehaviors
|
||||
- (NSDecimalNumber*) exceptionDuringOperation: (SEL)method
|
||||
error: (NSCalculationError)error
|
||||
leftOperand: (NSDecimalNumber*)leftOperand
|
||||
rightOperand: (NSDecimalNumber*)rightOperand
|
||||
{
|
||||
return [[isa defaultBehavior] exceptionDuringOperation: method
|
||||
error: error
|
||||
leftOperand: leftOperand
|
||||
rightOperand: rightOperand];
|
||||
}
|
||||
|
||||
- (NSRoundingMode) roundingMode
|
||||
{
|
||||
return [[isa defaultBehavior] roundingMode];
|
||||
}
|
||||
|
||||
- (short) scale
|
||||
{
|
||||
return [[isa defaultBehavior] scale];
|
||||
}
|
||||
|
||||
@end
|
Loading…
Add table
Add a link
Reference in a new issue