]> err.no Git - sope/blob - libFoundation/Foundation/NSDecimalNumber.m
fixed some NGMail framework build issue
[sope] / libFoundation / Foundation / NSDecimalNumber.m
1 /* 
2    NSDecimalNumber.m
3
4    Copyright (C) 2001, MDlink online service center GmbH, Helge Hess
5    All rights reserved.
6
7    Author: Helge Hess <helge.hess@mdlink.de>
8
9    This file is part of libFoundation.
10
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
15    documentation.
16
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.
23 */
24
25 #include <Foundation/NSDecimalNumber.h>
26 #include <Foundation/NSUtilities.h>
27 #include <common.h>
28 #include <math.h>
29
30 @interface NSDecimalZeroNumber : NSDecimalNumber
31 @end
32
33 @interface NSDecimalOneNumber : NSDecimalNumber
34 @end
35
36 @interface NSDecimalNotANumber : NSDecimalNumber
37 @end
38
39 @implementation NSDecimalNumber
40
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
45
46 + (void)setDefaultBehavior:(id<NSDecimalNumberBehaviors>)_beh
47 {
48   ASSIGN(defBehavior, _beh);
49 }
50 + (id<NSDecimalNumberBehaviors>)defaultBehavior
51 {
52   return defBehavior;
53 }
54
55 + (NSDecimalNumber *)zero
56 {
57   if (zero == nil)
58     zero = [[NSDecimalZeroNumber alloc] init];
59   return zero;
60 }
61 + (NSDecimalNumber *)one
62 {
63   if (one == nil)
64     one = [[NSDecimalOneNumber alloc] init];
65   return one;
66 }
67 + (NSDecimalNumber *)notANumber
68 {
69   if (nan == nil)
70     nan = [[NSDecimalNotANumber alloc] init];
71   return nan;
72 }
73
74 + (NSDecimalNumber *)maximumDecimalNumber
75 {
76   return [self notImplemented:_cmd];
77 }
78 + (NSDecimalNumber *)minimumDecimalNumber
79 {
80   return [self notImplemented:_cmd];
81 }
82
83 + (NSDecimalNumber *)decimalNumberWithDecimal:(NSDecimal)_num
84 {
85   return AUTORELEASE([[self alloc] initWithDecimal:_num]);
86 }
87 + (NSDecimalNumber *)decimalNumberWithMantissa:(unsigned long long)_mantissa
88   exponent:(short)_exp
89   isNegative:(BOOL)_flag
90 {
91   return AUTORELEASE([[self alloc] initWithMantissa:_mantissa
92                                    exponent:_exp isNegative:_flag]);
93 }
94
95 + (NSDecimalNumber *)decimalNumberWithString:(NSString *)_s
96 {
97   return AUTORELEASE([[self alloc] initWithString:_s]);
98 }
99 + (NSDecimalNumber *)decimalNumberWithString:(NSString *)_s
100   locale:(NSDictionary *)_locale
101 {
102   return AUTORELEASE([[self alloc] initWithString:_s locale:_locale]);
103 }
104
105 + (NSDecimalNumber *)decimalNumberWithNumber:(NSNumber *)_number
106 {
107   /* TO BE FIXED ! */
108   return (id)[self numberWithDouble:[_number doubleValue]];
109 }
110
111 - (id)initWithDecimal:(NSDecimal)_num
112 {
113   /* designated initializer */
114   if (_num.exponent == 0) {
115     if (_num.mantissa == 0) {
116       RELEASE(self);
117       if (zero) return RETAIN(zero);
118       return [[[self class] zero] retain];
119     }
120     else if (_num.mantissa == 1) {
121       RELEASE(self);
122       if (one) return RETAIN(one);
123       return [[[self class] one] retain];
124     }
125   }
126   
127   self->decimal = _num;
128   return self;
129 }
130 - (id)init
131 {
132   return [self initWithMantissa:0 exponent:0 isNegative:NO];
133 }
134
135 - (id)initWithMantissa:(unsigned long long)_mantissa
136   exponent:(short)_exp
137   isNegative:(BOOL)_flag
138 {
139   NSDecimal d;
140   d.mantissa   = _mantissa;
141   d.exponent   = _exp;
142   d.isNegative = _flag ? YES : NO;
143   return [self initWithDecimal:d];
144 }
145
146 - (id)initWithString:(NSString *)_s locale:(NSDictionary *)_locale
147 {
148   return [self initWithDouble:[_s doubleValue]];
149 }
150 - (id)initWithString:(NSString *)_s
151 {
152   return [self initWithString:_s locale:nil];
153 }
154
155 /* integer init's */
156
157 - (id)initWithBool:(BOOL)value
158 {
159   return [self initWithInt:value ? 1 : 0];
160 }
161 - (id)initWithChar:(char)value
162 {
163   return [self initWithInt:value];
164 }
165 - (id)initWithUnsignedChar:(unsigned char)value
166 {
167   return [self initWithInt:value];
168 }
169 - (id)initWithShort:(short)value
170 {
171   return [self initWithInt:value];
172 }
173 - (id)initWithUnsignedShort:(unsigned short)value
174 {
175   return [self initWithInt:value];
176 }
177
178 - (id)initWithInt:(int)value
179 {
180   NSDecimal d;
181   d.exponent   = 0;
182   if (value < 0) {
183     d.mantissa   = -value;
184     d.isNegative = YES;
185   }
186   else {
187     d.mantissa   = value;
188     d.isNegative = NO;
189   }
190   return [self initWithDecimal:d];
191 }
192 - (id)initWithUnsignedInt:(unsigned int)value
193 {
194   NSDecimal d;
195   d.exponent   = 0;
196   d.mantissa   = value;
197   d.isNegative = NO;
198   return [self initWithDecimal:d];
199 }
200
201 - (id)initWithLong:(long)value
202 {
203   NSDecimal d;
204   d.exponent   = 0;
205   if (value < 0) {
206     d.mantissa   = -value;
207     d.isNegative = YES;
208   }
209   else {
210     d.mantissa   = value;
211     d.isNegative = NO;
212   }
213   return [self initWithDecimal:d];
214 }
215 - (id)initWithUnsignedLong:(unsigned long)value
216 {
217   NSDecimal d;
218   d.exponent   = 0;
219   d.mantissa   = value;
220   d.isNegative = NO;
221   return [self initWithDecimal:d];
222 }
223
224 - (id)initWithLongLong:(long long)value
225 {
226   NSDecimal d;
227   d.exponent   = 0;
228   if (value < 0) {
229     d.mantissa   = -value;
230     d.isNegative = YES;
231   }
232   else {
233     d.mantissa   = value;
234     d.isNegative = NO;
235   }
236   return [self initWithDecimal:d];
237 }
238 - (id)initWithUnsignedLongLong:(unsigned long long)value
239 {
240   NSDecimal d;
241   d.exponent   = 0;
242   d.mantissa   = value;
243   d.isNegative = NO;
244   return [self initWithDecimal:d];
245 }
246
247 /* floating point inits */
248
249 - (id)initWithFloat:(float)value
250 {
251   return [self initWithDouble:(double)value];
252 }
253 - (id)initWithDouble:(double)value
254 {
255   char buf[128];
256   char      *comma, *start;
257   NSDecimal d;
258   
259   /* TODO: snprintf doesn't seem to exist on Solaris 2.5, add to configure */
260   if (snprintf(buf, sizeof(buf), "%g", value) < 1) {
261     RELEASE(self);
262     return nil;
263   }
264   
265   d.isNegative = value < 0.0 ? YES : NO;
266   
267   start = d.isNegative ? &(buf[1]) : buf; /* strip the minus */
268   
269   if ((comma = index(buf, '.'))) {
270     /* decimal sep */
271     unsigned long int vk, nk;
272     *comma = '\0';
273     comma++;
274     sscanf(start, "%lu", &vk);
275     sscanf(comma, "%lu", &nk);
276     d.exponent = strlen(comma);
277     d.mantissa = vk * d.exponent + nk;
278   }
279   else {
280     /* no decimal sep */
281     unsigned long int vk;
282     sscanf(start, "%lu", &vk);
283     d.exponent = 0;
284     d.mantissa = vk;
285   }
286   return [self initWithDecimal:d];
287 }
288
289 /* type */
290
291 - (const char *)objCType
292 {
293   return "d";
294 }
295
296 /* values */
297
298 - (int)intValue
299 {
300   if (self->decimal.exponent == 0) {
301     return self->decimal.isNegative
302       ? -(self->decimal.mantissa)
303       : self->decimal.mantissa;
304   }
305   return [self doubleValue];
306 }
307 - (BOOL)boolValue
308 {
309   return [self intValue] ? YES : NO;
310 }
311 - (char)charValue
312 {
313   return [self intValue];
314 }
315 - (unsigned char)unsignedCharValue
316 {
317   return [self intValue];
318 }
319 - (short)shortValue
320 {
321   return [self intValue];
322 }
323 - (unsigned short)unsignedShortValue
324 {
325   return [self intValue];
326 }
327
328 - (unsigned int)unsignedIntValue
329 {
330   if (self->decimal.exponent == 0 && !self->decimal.isNegative)
331     return self->decimal.mantissa;
332   return [self doubleValue];
333 }
334 - (long)longValue
335 {
336   return [self doubleValue];
337 }
338 - (unsigned long)unsignedLongValue
339 {
340   if (self->decimal.exponent == 0 && !self->decimal.isNegative)
341     return self->decimal.mantissa;
342   return [self doubleValue];
343 }
344 - (long long)longLongValue
345 {
346   return [self doubleValue];
347 }
348 - (unsigned long long)unsignedLongLongValue
349 {
350   if (self->decimal.exponent == 0 && !self->decimal.isNegative)
351     return self->decimal.mantissa;
352   return [self doubleValue];
353 }
354 - (float)floatValue
355 {
356   return [self doubleValue];
357 }
358
359 - (double)doubleValue
360 {
361   double d;
362   
363   d = (self->decimal.exponent == 0)
364     ? (double)self->decimal.mantissa
365     : ((double)self->decimal.mantissa) * pow(10, self->decimal.exponent);
366   
367   if (self->decimal.isNegative) d = -d;
368   
369   return d;
370 }
371
372 - (NSDecimal)decimalValue
373 {
374   return self->decimal;
375 }
376
377 /* operations */
378
379 - (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)_num
380 {
381   return [self decimalNumberByAdding:_num withBehavior:defBehavior];
382 }
383 - (NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)_num
384 {
385   return [self decimalNumberBySubtracting:_num withBehavior:defBehavior];
386 }
387 - (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)_num
388 {
389   return [self decimalNumberByMultiplyingBy:_num withBehavior:defBehavior];
390 }
391 - (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)_num
392 {
393   return [self decimalNumberByDividingBy:_num withBehavior:defBehavior];
394 }
395
396 - (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)_num
397   withBehavior:(id<NSDecimalNumberBehaviors>)_beh
398 {
399   NSDecimal          res, r;
400   NSCalculationError err;
401   
402   r = [_num decimalValue];
403   
404   err = NSDecimalAdd(&res, &(self->decimal), &r, [_beh roundingMode]);
405   
406   if (err != NSCalculationOK) {
407     return [_beh exceptionDuringOperation:_cmd
408                  error:err
409                  leftOperand:self
410                  rightOperand:_num];
411   }
412   
413   return [NSDecimalNumber decimalNumberWithDecimal:res];
414 }
415
416 - (NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)_num
417   withBehavior:(id<NSDecimalNumberBehaviors>)_beh
418 {
419   NSDecimal          res, r;
420   NSCalculationError err;
421   
422   r = [_num decimalValue];
423   
424   err = NSDecimalSubtract(&res, &(self->decimal), &r, [_beh roundingMode]);
425   
426   if (err != NSCalculationOK) {
427     return [_beh exceptionDuringOperation:_cmd
428                  error:err
429                  leftOperand:self
430                  rightOperand:_num];
431   }
432   
433   return [NSDecimalNumber decimalNumberWithDecimal:res];
434 }
435
436 - (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)_num
437   withBehavior:(id<NSDecimalNumberBehaviors>)_beh
438 {
439   NSDecimal          res, r;
440   NSCalculationError err;
441   
442   r = [_num decimalValue];
443   
444   err = NSDecimalMultiply(&res, &(self->decimal), &r, [_beh roundingMode]);
445   
446   if (err != NSCalculationOK) {
447     return [_beh exceptionDuringOperation:_cmd
448                  error:err
449                  leftOperand:self
450                  rightOperand:_num];
451   }
452   
453   return [NSDecimalNumber decimalNumberWithDecimal:res];
454 }
455
456 - (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)_num
457   withBehavior:(id<NSDecimalNumberBehaviors>)_beh
458 {
459   NSDecimal          res, r;
460   NSCalculationError err;
461   
462   r = [_num decimalValue];
463   
464   err = NSDecimalDivide(&res, &(self->decimal), &r, [_beh roundingMode]);
465   
466   if (err != NSCalculationOK) {
467     return [_beh exceptionDuringOperation:_cmd
468                  error:err
469                  leftOperand:self
470                  rightOperand:_num];
471   }
472   
473   return [NSDecimalNumber decimalNumberWithDecimal:res];
474 }
475
476 /* comparison */
477
478 - (NSComparisonResult)compareWithDecimalNumber:(NSDecimalNumber *)_num
479 {
480   return NSOrderedSame;
481 }
482 - (NSComparisonResult)compare:(NSNumber *)_num
483 {
484   NSDecimalNumber *num;
485   
486   if (_num == self) return NSOrderedSame;
487   
488   if ([_num isKindOfClass:[NSDecimalNumber class]])
489     num = (NSDecimalNumber *)_num;
490   else
491     num = [NSDecimalNumber decimalNumberWithNumber:_num];
492   
493   return [self compareWithDecimalNumber:num];
494 }
495
496 /* description */
497
498 - (NSString *)stringValue
499 {
500   return [self description];
501 }
502
503 - (NSString *)descriptionWithLocale:(NSDictionary *)_locale
504 {
505   return NSDecimalString(&(self->decimal), _locale);
506 }
507
508 - (NSString *)description
509 {
510   return [self descriptionWithLocale:nil];
511 }
512
513 @end /* NSDecimalNumber */
514
515 @implementation NSDecimalZeroNumber
516
517 - (id)init
518 {
519   self->decimal.exponent   = 0;
520   self->decimal.mantissa   = 0;
521   self->decimal.isNegative = NO;
522   return self;
523 }
524
525 /* operations */
526
527 - (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)_num
528   withBehavior:(id<NSDecimalNumberBehaviors>)_beh
529 {
530   return _num;
531 }
532
533 - (NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)_num
534   withBehavior:(id<NSDecimalNumberBehaviors>)_beh
535 {
536   NSDecimal d;
537   d = [_num decimalValue];
538   d.isNegative = d.isNegative ? NO : YES;
539   return [NSDecimalNumber decimalNumberWithDecimal:d];
540 }
541
542 - (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)_num
543   withBehavior:(id<NSDecimalNumberBehaviors>)_beh
544 {
545   return self;
546 }
547
548 - (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)_num
549   withBehavior:(id<NSDecimalNumberBehaviors>)_beh
550 {
551   /* should check for _num==zero ??? */
552   return self;
553 }
554
555 /* description */
556
557 - (NSString *)descriptionWithLocale:(NSDictionary *)_locale
558 {
559   return @"0";
560 }
561 - (NSString *)description
562 {
563   return @"0";
564 }
565
566 @end /* NSDecimalZeroNumber */
567
568 @implementation NSDecimalOneNumber
569
570 - (id)init
571 {
572   self->decimal.mantissa   = 1;
573   self->decimal.exponent   = 0;
574   self->decimal.isNegative = NO;
575   return self;
576 }
577
578 /* operations */
579
580 - (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)_num
581   withBehavior:(id<NSDecimalNumberBehaviors>)_beh
582 {
583   return _num;
584 }
585
586 - (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)_num
587   withBehavior:(id<NSDecimalNumberBehaviors>)_beh
588 {
589   /* 1 * x = x */
590   return _num;
591 }
592
593 /* description */
594
595 - (NSString *)descriptionWithLocale:(NSDictionary *)_locale
596 {
597   return @"1";
598 }
599 - (NSString *)description
600 {
601   return @"1";
602 }
603
604 @end /* NSDecimalOneNumber */
605
606 @implementation NSDecimalNotANumber
607
608 - (id)init
609 {
610   self->decimal.mantissa   = 1;
611   self->decimal.exponent   = 0;
612   self->decimal.isNegative = NO;
613   return self;
614 }
615
616 /* operations */
617
618 - (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)_num
619   withBehavior:(id<NSDecimalNumberBehaviors>)_beh
620 {
621   return self;
622 }
623 - (NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)_num
624   withBehavior:(id<NSDecimalNumberBehaviors>)_beh
625 {
626   return self;
627 }
628
629 - (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)_num
630   withBehavior:(id<NSDecimalNumberBehaviors>)_beh
631 {
632   return self;
633 }
634
635 - (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)_num
636   withBehavior:(id<NSDecimalNumberBehaviors>)_beh
637 {
638   /* should check for 0-divide ?? */
639   return self;
640 }
641
642 /* description */
643
644 - (NSString *)descriptionWithLocale:(NSDictionary *)_locale
645 {
646   return @"NaN";
647 }
648
649 @end /* NSDecimalNotANumber */
650
651 @implementation NSDecimalNumberHandler
652
653 - (NSDecimalNumber *)exceptionDuringOperation:(SEL)method
654   error:(NSCalculationError)_error
655   leftOperand:(NSDecimalNumber *)_lhs
656   rightOperand:(NSDecimalNumber *)_rhs
657 {
658   return nil;
659 }
660
661 - (NSRoundingMode)roundingMode {
662   return NSRoundBankers;
663 }
664
665 - (short)scale {
666   return 0;
667 }
668
669 @end /* NSDecimalNumberHandler */