[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC/RFA]: NSDecimalNumber initWithBytes:objCType:
From: |
David Ayers |
Subject: |
[RFC/RFA]: NSDecimalNumber initWithBytes:objCType: |
Date: |
Thu, 04 Jan 2007 22:47:37 +0100 |
User-agent: |
Mozilla Thunderbird 1.0.2 (X11/20061113) |
Hello,
This is similar crude approach short of using GMP directly in that
method. It basically adds handling for scalar types yet still relies on
a temporary string an parsing for double an float.
It does attempt to do some handling of nan and +/-inf. I propose this
patch for the trunk. The release branch should probably only add the
GSPrivateDefaultLocale.
The patch also add NAN handling for NSDecimalDouble.
>From Working on this patch, I think that the _public_ API, which only
includes ...
/** Give back the value of a NSDecimal as a double in (preallocated)
result. */
GS_EXPORT double
NSDecimalDouble(NSDecimal *number);
..., is missing the following conversion functions:
void GSFloatDecimal(NSDecimal *result, float value);
void GSDoubleDecimal(NSDecimal *result, double value);
void GSLongDoubleDecimal(NSDecimal *result, long double value);
These functions would be implemented via GMP where available or via
format string processing otherwise. Possibly the API should allow for
explicit precision:
void GSFloatDecimal(NSDecimal *result, float value, unsigned prec);
void GSDoubleDecimal(NSDecimal *result, double value, unsigned prec);
void GSLongDoubleDecimal(NSDecimal *result, long double value, unsigned
prec);
Cheers,
David
Index: Source/NSDecimalNumber.m
===================================================================
--- Source/NSDecimalNumber.m (Revision 24312)
+++ Source/NSDecimalNumber.m (Arbeitskopie)
@@ -26,6 +26,9 @@
$Date$ $Revision$
*/
+#define _GNU_SOURCE
+#include <math.h>
+
#include "Foundation/NSCoder.h"
#include "Foundation/NSDecimal.h"
#include "Foundation/NSDecimalNumber.h"
@@ -235,14 +238,146 @@
*/
- (id) initWithBytes: (const void*)value objCType: (const char*)type
{
- double tmp;
- NSString *s;
+ unsigned long long val;
+ long long llval;
+ NSDecimal decimal;
+ BOOL negative, llvalSet;
- memcpy(&tmp, value, sizeof(tmp));
- s = [[NSString alloc] initWithFormat: @"%g", tmp];
- self = [self initWithString: s];
- RELEASE(s);
- return self;
+ if (strlen(type) != 1)
+ {
+ DESTROY(self);
+ return nil;
+ }
+
+ llvalSet = YES;
+ negative = NO;
+
+ switch (*type)
+ {
+ case _C_CHR:
+ {
+ signed char v = *(signed char *)value;
+ llval = (long long)v;
+ break;
+ }
+ case _C_UCHR:
+ {
+ unsigned char v = *(unsigned char *)value;
+ llval = (long long)v;
+ break;
+ }
+ case _C_SHT:
+ {
+ short v = *(short *)value;
+ llval = (long long)v;
+ break;
+ }
+ case _C_USHT:
+ {
+ unsigned short v = *(unsigned short *)value;
+ llval = (long long)v;
+ break;
+ }
+ case _C_INT:
+ {
+ int v = *(int *)value;
+ llval = (long long)v;
+ break;
+ }
+ case _C_UINT:
+ {
+ unsigned int v = *(unsigned int *)value;
+ llval = (long long)v;
+ break;
+ }
+ case _C_LNG:
+ {
+ long v = *(long *)value;
+ llval = (long long)v;
+ break;
+ }
+ case _C_ULNG:
+ {
+ unsigned long v = *(unsigned long *)value;
+ llval = (long long)v;
+ break;
+ }
+#ifdef _C_LNGLNG
+ case _C_LNGLNG:
+#else
+ case 'q':
+#endif
+ {
+ long long v = *(long long *)value;
+ llval = (long long)v;
+ break;
+ }
+#ifdef _C_ULNGLNG
+ case _C_ULNGLNG:
+#else
+ case 'Q':
+#endif
+ default:
+ {
+ llvalSet = NO;
+ break;
+
+ }
+ }
+ if (llvalSet)
+ {
+ if (llval<0)
+ {
+ negative = YES;
+ llval *= -1;
+ }
+ val = llval;
+ }
+ else
+ {
+ switch (*type)
+ {
+ case _C_FLT:
+ {
+ NSString *s;
+ float v = *(float *)value;
+ if (isnanf(v)) return notANumber;
+ if (isinff(v)) return (v < 0.0) ? minNumber : maxNumber;
+ s = [[NSString alloc] initWithFormat: @"%g"
+ locale: GSPrivateDefaultLocale(), (double)v];
+ self = [self initWithString: s];
+ RELEASE(s);
+ return self;
+ break;
+ }
+ case _C_DBL:
+ {
+ NSString *s;
+ double v = *(double *)value;
+ if (isnan(v)) return notANumber;
+ if (isinf(v)) return (v < 0.0) ? minNumber : maxNumber;
+ s = [[NSString alloc] initWithFormat: @"%g"
+ locale: GSPrivateDefaultLocale(), v];
+ self = [self initWithString: s];
+ RELEASE(s);
+ return self;
+ break;
+ }
+#ifdef _C_ULNGLNG
+ case _C_ULNGLNG:
+#else
+ case 'Q':
+#endif
+ {
+ val = *(unsigned long long *)value;
+ break;
+ }
+ }
+ }
+
+ NSDecimalFromComponents(&decimal, val,
+ 0, negative);
+ return [self initWithDecimal: decimal];
}
- (id) initWithDecimal: (NSDecimal)decimal
Index: Source/NSDecimal.m
===================================================================
--- Source/NSDecimal.m (Revision 24312)
+++ Source/NSDecimal.m (Arbeitskopie)
@@ -26,6 +26,7 @@
$Date$ $Revision$
*/
+#define _GNU_SOURCE
#include <math.h>
#if !defined(__APPLE__) || !defined(GNU_RUNTIME)
#include <ctype.h>
@@ -35,6 +36,10 @@
#include "Foundation/NSDictionary.h"
#include "Foundation/NSUserDefaults.h"
+#ifndef NAN
+#define NAN 0.0
+#endif
+
/*
This file provides two implementations of the NSDecimal functions.
One is based on pure simple decimal mathematics, as we all learned it
@@ -910,8 +915,7 @@
int i;
if (!number->validNumber)
- // Somehow I dont have NAN defined on my machine
- return 0.0;
+ return NAN;
// Sum up the digits
for (i = 0; i < number->length; i++)
Index: base/NSDecimal/functions.m
===================================================================
--- base/NSDecimal/functions.m (Revision 0)
+++ base/NSDecimal/functions.m (Revision 0)
@@ -0,0 +1,38 @@
+#import "ObjectTesting.h"
+#import <Foundation/NSAutoreleasePool.h>
+#import <Foundation/NSString.h>
+#import <Foundation/NSDecimal.h>
+
+int
+main(int argc, char *argv[])
+{
+ CREATE_AUTORELEASE_POOL(arp);
+ NSDecimal dec1, dec2;
+ NSDictionary *noLocale;
+ NSString *string;
+
+ noLocale = [NSDictionary dictionary];
+
+ NSDecimalFromComponents(&dec1,0LL,0,0);
+ string = NSDecimalString(&dec1, noLocale);
+ pass([@"0.0" isEqual:string],"NSDecimalFromComponents(&dec,0,0,0)");
+
+ NSDecimalFromComponents(&dec1,0LL,0,1);
+ string = NSDecimalString(&dec1, noLocale);
+ pass([@"0.0" isEqual:string],"NSDecimalFromComponents(&dec,0,0,1)");
+
+ NSDecimalFromComponents(&dec1,10LL,0,0);
+ string = NSDecimalString(&dec1, noLocale);
+ pass([@"10" isEqual:string],"NSDecimalFromComponents(&dec,10,0,0)");
+
+ NSDecimalFromComponents(&dec1,100LL,0,0);
+ string = NSDecimalString(&dec1, noLocale);
+ pass([@"100" isEqual:string],"NSDecimalFromComponents(&dec,100,0,0)");
+
+ NSDecimalFromComponents(&dec1,10LL,1,0);
+ string = NSDecimalString(&dec1, noLocale);
+ pass([@"100" isEqual:string],"NSDecimalFromComponents(&dec,10,1,0)");
+
+ DESTROY(arp);
+ return 0;
+}
Index: base/NSDecimalNumber/creation.m
===================================================================
--- base/NSDecimalNumber/creation.m (Revision 0)
+++ base/NSDecimalNumber/creation.m (Revision 0)
@@ -0,0 +1,81 @@
+#import "ObjectTesting.h"
+#import <Foundation/NSAutoreleasePool.h>
+#import <Foundation/NSString.h>
+#import <Foundation/NSDecimalNumber.h>
+
+/* We avoid limits.h to remain portable.
+ The string constants in these tests may not be reliable. */
+
+signed char scm = -127;
+unsigned char ucm = 255;
+short ssm = -32767;
+unsigned short usm = 65535;
+int sim = 2147483647;
+unsigned int uim = 4294967295U;
+long slm = 2147483647;
+unsigned long ulm = 4294967295LU;
+float fm = 4294.967294;
+double dm = 4294.967294;
+
+int
+main(int argc, char *argv[])
+{
+ CREATE_AUTORELEASE_POOL(arp);
+ NSDecimalNumber *dec1, *dec2;
+ NSString *string1, *string2;
+
+ dec1 = [[NSDecimalNumber alloc] initWithBytes:&scm objCType: "c"];
+ string1 = [dec1 description];
+ string2 = @"-127";
+ pass([string1 isEqual:string2],"initWithBytes: _C_CHR");
+
+ dec1 = [[NSDecimalNumber alloc] initWithBytes:&ucm objCType: "C"];
+ string1 = [dec1 description];
+ string2 = @"255";
+ pass([string1 isEqual:string2],"initWithBytes: _C_UCHR");
+
+ dec1 = [[NSDecimalNumber alloc] initWithBytes:&ssm objCType: "s"];
+ string1 = [dec1 description];
+ string2 = @"-32767";
+ pass([string1 isEqual:string2],"initWithBytes: _C_SHRT");
+
+ dec1 = [[NSDecimalNumber alloc] initWithBytes:&usm objCType: "S"];
+ string1 = [dec1 description];
+ string2 = @"65535";
+ pass([string1 isEqual:string2],"initWithBytes: _C_USHRT");
+
+ dec1 = [[NSDecimalNumber alloc] initWithBytes:&sim objCType: "i"];
+ string1 = [dec1 description];
+ string2 = [NSString stringWithFormat:@"%i",sim];
+ string2 = @"2.147483647E9";
+ pass([string1 isEqual:string2],"initWithBytes: _C_INT");
+
+ dec1 = [[NSDecimalNumber alloc] initWithBytes:&uim objCType: "I"];
+ string1 = [dec1 description];
+ string2 = @"4.294967295E9";
+ pass([string1 isEqual:string2],"initWithBytes: _C_UINT");
+
+ dec1 = [[NSDecimalNumber alloc] initWithBytes:&slm objCType: "l"];
+ string1 = [dec1 description];
+ string2 = @"2.147483647E9";
+ pass([string1 isEqual:string2],"initWithBytes: _C_LONG");
+
+ dec1 = [[NSDecimalNumber alloc] initWithBytes:&ulm objCType: "L"];
+ string1 = [dec1 description];
+ string2 = @"4.294967295E9";
+ pass([string1 isEqual:string2],"initWithBytes: _C_ULONG");
+
+ dec1 = [[NSDecimalNumber alloc] initWithBytes:&fm objCType: "f"];
+ string1 = [dec1 description];
+ string2 = @"4294.97";
+ pass([string1 isEqual:string2],"initWithBytes: _C_FLT");
+
+ dec1 = [[NSDecimalNumber alloc] initWithBytes:&dm objCType: "d"];
+ string1 = [dec1 description];
+ string2 = @"4294.97";
+ pass([string1 isEqual:string2],"initWithBytes: _C_DBL");
+
+
+ DESTROY(arp);
+ return 0;
+}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [RFC/RFA]: NSDecimalNumber initWithBytes:objCType:,
David Ayers <=