4 Copyright (C) 2001, MDlink online service center GmbH, Helge Hess
7 Author: Helge Hess <helge.hess@mdlink.de>
9 This file is part of libFoundation.
11 Permission to use, copy, modify, and distribute this software and its
12 documentation for any purpose and without fee is hereby granted, provided
13 that the above copyright notice appear in all copies and that both that
14 copyright notice and this permission notice appear in supporting
17 We disclaim all warranties with regard to this software, including all
18 implied warranties of merchantability and fitness, in no event shall
19 we be liable for any special, indirect or consequential damages or any
20 damages whatsoever resulting from loss of use, data or profits, whether in
21 an action of contract, negligence or other tortious action, arising out of
22 or in connection with the use or performance of this software.
25 #include <Foundation/NSDecimalNumber.h>
26 #include <Foundation/NSUtilities.h>
30 @interface NSDecimalZeroNumber : NSDecimalNumber
33 @interface NSDecimalOneNumber : NSDecimalNumber
36 @interface NSDecimalNotANumber : NSDecimalNumber
39 @implementation NSDecimalNumber
41 static id<NSObject,NSDecimalNumberBehaviors> defBehavior = nil; // THREAD
42 static NSDecimalNumber *zero = nil; // THREAD
43 static NSDecimalNumber *one = nil; // THREAD
44 static NSDecimalNumber *nan = nil; // THREAD
46 + (void)setDefaultBehavior:(id<NSDecimalNumberBehaviors>)_beh
48 ASSIGN(defBehavior, _beh);
50 + (id<NSDecimalNumberBehaviors>)defaultBehavior
55 + (NSDecimalNumber *)zero
58 zero = [[NSDecimalZeroNumber alloc] init];
61 + (NSDecimalNumber *)one
64 one = [[NSDecimalOneNumber alloc] init];
67 + (NSDecimalNumber *)notANumber
70 nan = [[NSDecimalNotANumber alloc] init];
74 + (NSDecimalNumber *)maximumDecimalNumber
76 return [self notImplemented:_cmd];
78 + (NSDecimalNumber *)minimumDecimalNumber
80 return [self notImplemented:_cmd];
83 + (NSDecimalNumber *)decimalNumberWithDecimal:(NSDecimal)_num
85 return AUTORELEASE([[self alloc] initWithDecimal:_num]);
87 + (NSDecimalNumber *)decimalNumberWithMantissa:(unsigned long long)_mantissa
89 isNegative:(BOOL)_flag
91 return AUTORELEASE([[self alloc] initWithMantissa:_mantissa
92 exponent:_exp isNegative:_flag]);
95 + (NSDecimalNumber *)decimalNumberWithString:(NSString *)_s
97 return AUTORELEASE([[self alloc] initWithString:_s]);
99 + (NSDecimalNumber *)decimalNumberWithString:(NSString *)_s
100 locale:(NSDictionary *)_locale
102 return AUTORELEASE([[self alloc] initWithString:_s locale:_locale]);
105 + (NSDecimalNumber *)decimalNumberWithNumber:(NSNumber *)_number
108 return (id)[self numberWithDouble:[_number doubleValue]];
111 - (id)initWithDecimal:(NSDecimal)_num
113 /* designated initializer */
114 if (_num.exponent == 0) {
115 if (_num.mantissa == 0) {
117 if (zero) return RETAIN(zero);
118 return [[[self class] zero] retain];
120 else if (_num.mantissa == 1) {
122 if (one) return RETAIN(one);
123 return [[[self class] one] retain];
127 self->decimal = _num;
132 return [self initWithMantissa:0 exponent:0 isNegative:NO];
135 - (id)initWithMantissa:(unsigned long long)_mantissa
137 isNegative:(BOOL)_flag
140 d.mantissa = _mantissa;
142 d.isNegative = _flag ? YES : NO;
143 return [self initWithDecimal:d];
146 - (id)initWithString:(NSString *)_s locale:(NSDictionary *)_locale
148 return [self initWithDouble:[_s doubleValue]];
150 - (id)initWithString:(NSString *)_s
152 return [self initWithString:_s locale:nil];
157 - (id)initWithBool:(BOOL)value
159 return [self initWithInt:value ? 1 : 0];
161 - (id)initWithChar:(char)value
163 return [self initWithInt:value];
165 - (id)initWithUnsignedChar:(unsigned char)value
167 return [self initWithInt:value];
169 - (id)initWithShort:(short)value
171 return [self initWithInt:value];
173 - (id)initWithUnsignedShort:(unsigned short)value
175 return [self initWithInt:value];
178 - (id)initWithInt:(int)value
190 return [self initWithDecimal:d];
192 - (id)initWithUnsignedInt:(unsigned int)value
198 return [self initWithDecimal:d];
201 - (id)initWithLong:(long)value
213 return [self initWithDecimal:d];
215 - (id)initWithUnsignedLong:(unsigned long)value
221 return [self initWithDecimal:d];
224 - (id)initWithLongLong:(long long)value
236 return [self initWithDecimal:d];
238 - (id)initWithUnsignedLongLong:(unsigned long long)value
244 return [self initWithDecimal:d];
247 /* floating point inits */
249 - (id)initWithFloat:(float)value
251 return [self initWithDouble:(double)value];
253 - (id)initWithDouble:(double)value
259 /* TODO: snprintf doesn't seem to exist on Solaris 2.5, add to configure */
260 if (snprintf(buf, sizeof(buf), "%g", value) < 1) {
265 d.isNegative = value < 0.0 ? YES : NO;
267 start = d.isNegative ? &(buf[1]) : buf; /* strip the minus */
269 if ((comma = index(buf, '.'))) {
271 unsigned long int vk, nk;
274 sscanf(start, "%lu", &vk);
275 sscanf(comma, "%lu", &nk);
276 d.exponent = strlen(comma);
277 d.mantissa = vk * d.exponent + nk;
281 unsigned long int vk;
282 sscanf(start, "%lu", &vk);
286 return [self initWithDecimal:d];
291 - (const char *)objCType
300 if (self->decimal.exponent == 0) {
301 return self->decimal.isNegative
302 ? -(self->decimal.mantissa)
303 : self->decimal.mantissa;
305 return [self doubleValue];
309 return [self intValue] ? YES : NO;
313 return [self intValue];
315 - (unsigned char)unsignedCharValue
317 return [self intValue];
321 return [self intValue];
323 - (unsigned short)unsignedShortValue
325 return [self intValue];
328 - (unsigned int)unsignedIntValue
330 if (self->decimal.exponent == 0 && !self->decimal.isNegative)
331 return self->decimal.mantissa;
332 return [self doubleValue];
336 return [self doubleValue];
338 - (unsigned long)unsignedLongValue
340 if (self->decimal.exponent == 0 && !self->decimal.isNegative)
341 return self->decimal.mantissa;
342 return [self doubleValue];
344 - (long long)longLongValue
346 return [self doubleValue];
348 - (unsigned long long)unsignedLongLongValue
350 if (self->decimal.exponent == 0 && !self->decimal.isNegative)
351 return self->decimal.mantissa;
352 return [self doubleValue];
356 return [self doubleValue];
359 - (double)doubleValue
363 d = (self->decimal.exponent == 0)
364 ? (double)self->decimal.mantissa
365 : ((double)self->decimal.mantissa) * pow(10, self->decimal.exponent);
367 if (self->decimal.isNegative) d = -d;
372 - (NSDecimal)decimalValue
374 return self->decimal;
379 - (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)_num
381 return [self decimalNumberByAdding:_num withBehavior:defBehavior];
383 - (NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)_num
385 return [self decimalNumberBySubtracting:_num withBehavior:defBehavior];
387 - (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)_num
389 return [self decimalNumberByMultiplyingBy:_num withBehavior:defBehavior];
391 - (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)_num
393 return [self decimalNumberByDividingBy:_num withBehavior:defBehavior];
396 - (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)_num
397 withBehavior:(id<NSDecimalNumberBehaviors>)_beh
400 NSCalculationError err;
402 r = [_num decimalValue];
404 err = NSDecimalAdd(&res, &(self->decimal), &r, [_beh roundingMode]);
406 if (err != NSCalculationOK) {
407 return [_beh exceptionDuringOperation:_cmd
413 return [NSDecimalNumber decimalNumberWithDecimal:res];
416 - (NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)_num
417 withBehavior:(id<NSDecimalNumberBehaviors>)_beh
420 NSCalculationError err;
422 r = [_num decimalValue];
424 err = NSDecimalSubtract(&res, &(self->decimal), &r, [_beh roundingMode]);
426 if (err != NSCalculationOK) {
427 return [_beh exceptionDuringOperation:_cmd
433 return [NSDecimalNumber decimalNumberWithDecimal:res];
436 - (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)_num
437 withBehavior:(id<NSDecimalNumberBehaviors>)_beh
440 NSCalculationError err;
442 r = [_num decimalValue];
444 err = NSDecimalMultiply(&res, &(self->decimal), &r, [_beh roundingMode]);
446 if (err != NSCalculationOK) {
447 return [_beh exceptionDuringOperation:_cmd
453 return [NSDecimalNumber decimalNumberWithDecimal:res];
456 - (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)_num
457 withBehavior:(id<NSDecimalNumberBehaviors>)_beh
460 NSCalculationError err;
462 r = [_num decimalValue];
464 err = NSDecimalDivide(&res, &(self->decimal), &r, [_beh roundingMode]);
466 if (err != NSCalculationOK) {
467 return [_beh exceptionDuringOperation:_cmd
473 return [NSDecimalNumber decimalNumberWithDecimal:res];
478 - (NSComparisonResult)compareWithDecimalNumber:(NSDecimalNumber *)_num
480 return NSOrderedSame;
482 - (NSComparisonResult)compare:(NSNumber *)_num
484 NSDecimalNumber *num;
486 if (_num == self) return NSOrderedSame;
488 if ([_num isKindOfClass:[NSDecimalNumber class]])
489 num = (NSDecimalNumber *)_num;
491 num = [NSDecimalNumber decimalNumberWithNumber:_num];
493 return [self compareWithDecimalNumber:num];
498 - (NSString *)stringValue
500 return [self description];
503 - (NSString *)descriptionWithLocale:(NSDictionary *)_locale
505 return NSDecimalString(&(self->decimal), _locale);
508 - (NSString *)description
510 return [self descriptionWithLocale:nil];
513 @end /* NSDecimalNumber */
515 @implementation NSDecimalZeroNumber
519 self->decimal.exponent = 0;
520 self->decimal.mantissa = 0;
521 self->decimal.isNegative = NO;
527 - (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)_num
528 withBehavior:(id<NSDecimalNumberBehaviors>)_beh
533 - (NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)_num
534 withBehavior:(id<NSDecimalNumberBehaviors>)_beh
537 d = [_num decimalValue];
538 d.isNegative = d.isNegative ? NO : YES;
539 return [NSDecimalNumber decimalNumberWithDecimal:d];
542 - (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)_num
543 withBehavior:(id<NSDecimalNumberBehaviors>)_beh
548 - (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)_num
549 withBehavior:(id<NSDecimalNumberBehaviors>)_beh
551 /* should check for _num==zero ??? */
557 - (NSString *)descriptionWithLocale:(NSDictionary *)_locale
561 - (NSString *)description
566 @end /* NSDecimalZeroNumber */
568 @implementation NSDecimalOneNumber
572 self->decimal.mantissa = 1;
573 self->decimal.exponent = 0;
574 self->decimal.isNegative = NO;
580 - (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)_num
581 withBehavior:(id<NSDecimalNumberBehaviors>)_beh
586 - (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)_num
587 withBehavior:(id<NSDecimalNumberBehaviors>)_beh
595 - (NSString *)descriptionWithLocale:(NSDictionary *)_locale
599 - (NSString *)description
604 @end /* NSDecimalOneNumber */
606 @implementation NSDecimalNotANumber
610 self->decimal.mantissa = 1;
611 self->decimal.exponent = 0;
612 self->decimal.isNegative = NO;
618 - (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)_num
619 withBehavior:(id<NSDecimalNumberBehaviors>)_beh
623 - (NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)_num
624 withBehavior:(id<NSDecimalNumberBehaviors>)_beh
629 - (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)_num
630 withBehavior:(id<NSDecimalNumberBehaviors>)_beh
635 - (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)_num
636 withBehavior:(id<NSDecimalNumberBehaviors>)_beh
638 /* should check for 0-divide ?? */
644 - (NSString *)descriptionWithLocale:(NSDictionary *)_locale
649 @end /* NSDecimalNotANumber */
651 @implementation NSDecimalNumberHandler
653 - (NSDecimalNumber *)exceptionDuringOperation:(SEL)method
654 error:(NSCalculationError)_error
655 leftOperand:(NSDecimalNumber *)_lhs
656 rightOperand:(NSDecimalNumber *)_rhs
661 - (NSRoundingMode)roundingMode {
662 return NSRoundBankers;
669 @end /* NSDecimalNumberHandler */