gnustep-dev
[Top][All Lists]
Advanced

[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;
+}

reply via email to

[Prev in Thread] Current Thread [Next in Thread]