dec_number 0.1.6 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +2 -8
- data/dec_number.gemspec +1 -1
- data/ext/dec_number/decNumber/libdecNumber.a +0 -0
- data/ext/dec_number/dec_number.c +154 -6
- metadata +2 -2
data/README
CHANGED
@@ -1,20 +1,14 @@
|
|
1
|
-
WARNING! Pre-release, not finished.
|
2
|
-
|
3
1
|
DecNumber is a wrapper around ICU-decNumber (Copyright (c) IBM Corporation)
|
4
2
|
that subclasses Numeric.
|
5
3
|
|
6
4
|
The main benefit over BigDecimal and other things is that each instance carries it's own context around with it in a DecContext object. The context is what dertimines the precision and rounding behavior.
|
7
5
|
|
8
|
-
An example
|
9
|
-
|
10
|
-
Another example is a database with Decimal columns with differing precision and where you can't accept using Floats.
|
11
|
-
|
12
|
-
Another use case would be bitcoin, where you need an arbitrary precision, mixed with dollars.
|
6
|
+
An example is a database with Decimal columns with differing precision and where you can't accept using Floats.
|
13
7
|
|
14
8
|
I don't expect to instantiate these object directly, instead I will bind them to SQL Decimal in an ORM, or using some sort of Money class.
|
15
9
|
|
16
10
|
If you'd like to help out, please write tests!
|
17
11
|
|
18
|
-
Currently they
|
12
|
+
Currently they try to give you back DecNumber objects whenever used, including as the rval with another Numeric.
|
19
13
|
|
20
14
|
TODO: Most of the methods should accept a context as an argument. Currently the context is attached to the receiver.
|
data/dec_number.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s| # -*-ruby-*-
|
2
2
|
s.name = "dec_number"
|
3
|
-
s.version = '0.
|
3
|
+
s.version = '0.2.0'
|
4
4
|
s.authors = ["Paris Sinclair"]
|
5
5
|
s.email = ["paris@rubypanther.com"]
|
6
6
|
s.summary = "ICU-decNumber wrapper for arbitrary precision math with context objects"
|
Binary file
|
data/ext/dec_number/dec_number.c
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
#include "ruby.h"
|
2
2
|
#define DECNUMDIGITS 34
|
3
|
+
#define DECSUBSET 0
|
3
4
|
#include "decNumber.h"
|
4
5
|
#include <stdio.h>
|
5
6
|
|
@@ -54,6 +55,9 @@ VALUE cDecContext;
|
|
54
55
|
result = rb_funcall( cDecNumber, rb_intern("new"), 0 ); \
|
55
56
|
Data_Get_Struct(result, decNumber, result_ptr)
|
56
57
|
|
58
|
+
/*****
|
59
|
+
DecContext
|
60
|
+
*****/
|
57
61
|
static VALUE con_alloc(VALUE klass) {
|
58
62
|
decContext self_struct, *self_ptr;
|
59
63
|
VALUE self;
|
@@ -62,21 +66,108 @@ static VALUE con_alloc(VALUE klass) {
|
|
62
66
|
return self;
|
63
67
|
}
|
64
68
|
|
69
|
+
static VALUE con_set_digits(VALUE self, VALUE new_value) {
|
70
|
+
decContext *self_ptr;
|
71
|
+
Data_Get_Struct(self, decContext, self_ptr);
|
72
|
+
self_ptr->digits = FIX2INT(new_value);
|
73
|
+
return INT2FIX(self_ptr->digits);
|
74
|
+
}
|
75
|
+
|
65
76
|
static VALUE con_initialize(int argc, VALUE *argv, VALUE self) {
|
66
77
|
decContext *self_ptr;
|
67
|
-
VALUE
|
68
|
-
rb_scan_args( argc, argv, "01", &
|
78
|
+
VALUE digits;
|
79
|
+
rb_scan_args( argc, argv, "01", &digits );
|
69
80
|
|
70
81
|
Data_Get_Struct(self, decContext, self_ptr);
|
71
82
|
decContextDefault(self_ptr, DEC_INIT_BASE);
|
72
83
|
self_ptr->traps = 0; // no traps TODO: error handling
|
73
|
-
|
84
|
+
|
85
|
+
if ( NIL_P(digits) ) {
|
86
|
+
self_ptr->digits = DECNUMDIGITS;
|
87
|
+
} else {
|
88
|
+
con_set_digits(self,digits);
|
89
|
+
}
|
74
90
|
|
75
91
|
// TODO: Handle arguments
|
76
92
|
|
77
93
|
return self;
|
78
94
|
}
|
79
95
|
|
96
|
+
static VALUE con_get_rounding(VALUE self) {
|
97
|
+
decContext *self_ptr;
|
98
|
+
enum rounding round;
|
99
|
+
VALUE name_sym, rounding_names;
|
100
|
+
Data_Get_Struct(self, decContext, self_ptr);
|
101
|
+
round = decContextGetRounding(self_ptr);
|
102
|
+
rounding_names = rb_const_get( cDecContext, rb_intern("ROUNDING_NAMES") );
|
103
|
+
name_sym = rb_hash_aref( rounding_names, INT2FIX(round) );
|
104
|
+
return name_sym;
|
105
|
+
}
|
106
|
+
|
107
|
+
static VALUE con_set_rounding(VALUE self, VALUE new_rounding) {
|
108
|
+
decContext *self_ptr;
|
109
|
+
enum rounding round;
|
110
|
+
VALUE rounding_numbers;
|
111
|
+
|
112
|
+
Data_Get_Struct(self, decContext, self_ptr);
|
113
|
+
|
114
|
+
if ( SYMBOL_P( new_rounding ) ) {
|
115
|
+
rounding_numbers = rb_const_get( cDecContext, rb_intern("ROUNDING_NUMBERS") );
|
116
|
+
new_rounding = rb_hash_aref( rounding_numbers, new_rounding );
|
117
|
+
}
|
118
|
+
if( ! FIXNUM_P( new_rounding ) ) {
|
119
|
+
rb_raise(rb_eTypeError, "wrong argument type");
|
120
|
+
}
|
121
|
+
|
122
|
+
round = FIX2INT(new_rounding);
|
123
|
+
decContextSetRounding(self_ptr,round);
|
124
|
+
return new_rounding;
|
125
|
+
}
|
126
|
+
|
127
|
+
static VALUE con_get_digits(VALUE self) {
|
128
|
+
decContext *self_ptr;
|
129
|
+
int digits;
|
130
|
+
VALUE r_fixnum;
|
131
|
+
|
132
|
+
Data_Get_Struct(self, decContext, self_ptr);
|
133
|
+
digits = self_ptr->digits;
|
134
|
+
r_fixnum = INT2FIX(digits);
|
135
|
+
|
136
|
+
return r_fixnum;
|
137
|
+
}
|
138
|
+
|
139
|
+
static VALUE con_get_emin(VALUE self) {
|
140
|
+
decContext *self_ptr;
|
141
|
+
Data_Get_Struct(self, decContext, self_ptr);
|
142
|
+
return INT2FIX(self_ptr->emin);
|
143
|
+
}
|
144
|
+
|
145
|
+
static VALUE con_set_emin(VALUE self, VALUE new_value) {
|
146
|
+
decContext *self_ptr;
|
147
|
+
Data_Get_Struct(self, decContext, self_ptr);
|
148
|
+
self_ptr->emin = FIX2INT(new_value);
|
149
|
+
return INT2FIX(self_ptr->emin);
|
150
|
+
}
|
151
|
+
|
152
|
+
static VALUE con_get_emax(VALUE self) {
|
153
|
+
decContext *self_ptr;
|
154
|
+
Data_Get_Struct(self, decContext, self_ptr);
|
155
|
+
return INT2FIX(self_ptr->emax);
|
156
|
+
}
|
157
|
+
|
158
|
+
static VALUE con_set_emax(VALUE self, VALUE new_value) {
|
159
|
+
decContext *self_ptr;
|
160
|
+
Data_Get_Struct(self, decContext, self_ptr);
|
161
|
+
self_ptr->emax = FIX2INT(new_value);
|
162
|
+
return INT2FIX(self_ptr->emax);
|
163
|
+
}
|
164
|
+
// /DecContext
|
165
|
+
|
166
|
+
|
167
|
+
/*****
|
168
|
+
DecNumber
|
169
|
+
*****/
|
170
|
+
|
80
171
|
static VALUE num_alloc(VALUE klass) {
|
81
172
|
decNumber self_struct, *self_ptr;
|
82
173
|
decContext context;
|
@@ -92,10 +183,10 @@ static VALUE num_alloc(VALUE klass) {
|
|
92
183
|
static VALUE num_initialize(int argc, VALUE *argv, VALUE self) {
|
93
184
|
decNumber *self_ptr;
|
94
185
|
decContext *context_ptr;
|
95
|
-
VALUE from, r_str, context;
|
186
|
+
VALUE from, r_str, context, digits;
|
96
187
|
|
97
|
-
rb_scan_args( argc, argv, "
|
98
|
-
context = rb_funcall( cDecContext, rb_intern("new"),
|
188
|
+
rb_scan_args( argc, argv, "02", &from, &digits );
|
189
|
+
context = rb_funcall( cDecContext, rb_intern("new"), 1, digits );
|
99
190
|
rb_iv_set( self, "@context", context );
|
100
191
|
Data_Get_Struct(context, decContext, context_ptr);
|
101
192
|
Data_Get_Struct(self, decNumber, self_ptr);
|
@@ -447,12 +538,69 @@ static VALUE num_power(VALUE self, VALUE rval) {
|
|
447
538
|
return result;
|
448
539
|
}
|
449
540
|
|
541
|
+
void con_setup_rounding_constant( VALUE rounding_names, VALUE rounding_numbers, const char *sym_name, const char *const_name, enum rounding round ) {
|
542
|
+
VALUE round_num, round_sym;
|
543
|
+
round_num = INT2FIX(round);
|
544
|
+
round_sym = ID2SYM(rb_intern(sym_name));
|
545
|
+
rb_define_const( cDecContext, const_name, round_num );
|
546
|
+
rb_hash_aset( rounding_names, round_num, round_sym );
|
547
|
+
rb_hash_aset( rounding_numbers, round_sym, round_num );
|
548
|
+
return;
|
549
|
+
}
|
550
|
+
|
450
551
|
void Init_dec_number() {
|
552
|
+
/****
|
553
|
+
DecContext
|
554
|
+
****/
|
555
|
+
|
556
|
+
// *** constants and enums
|
557
|
+
enum rounding round;
|
558
|
+
VALUE rounding_names, rounding_numbers, round_default_num;
|
451
559
|
cDecContext = rb_define_class("DecContext", rb_cObject);
|
560
|
+
rounding_names = rb_hash_new();
|
561
|
+
rb_define_const( cDecContext, "ROUNDING_NAMES", rounding_names );
|
562
|
+
rounding_numbers = rb_hash_new();
|
563
|
+
rb_define_const( cDecContext, "ROUNDING_NUMBERS", rounding_numbers );
|
564
|
+
con_setup_rounding_constant( rounding_names, rounding_numbers,
|
565
|
+
"ceil", "ROUND_CEIL", DEC_ROUND_CEILING );
|
566
|
+
con_setup_rounding_constant( rounding_names, rounding_numbers,
|
567
|
+
"down", "ROUND_DOWN", DEC_ROUND_DOWN );
|
568
|
+
con_setup_rounding_constant( rounding_names, rounding_numbers,
|
569
|
+
"floor", "ROUND_FLOOR", DEC_ROUND_FLOOR );
|
570
|
+
con_setup_rounding_constant( rounding_names, rounding_numbers,
|
571
|
+
"half_down", "ROUND_HALF_DOWN", DEC_ROUND_HALF_DOWN );
|
572
|
+
con_setup_rounding_constant( rounding_names, rounding_numbers,
|
573
|
+
"half_even", "ROUND_HALF_EVEN", DEC_ROUND_HALF_EVEN );
|
574
|
+
con_setup_rounding_constant( rounding_names, rounding_numbers,
|
575
|
+
"half_up", "ROUND_HALF_UP", DEC_ROUND_HALF_UP );
|
576
|
+
con_setup_rounding_constant( rounding_names, rounding_numbers,
|
577
|
+
"up", "ROUND_UP", DEC_ROUND_UP );
|
578
|
+
con_setup_rounding_constant( rounding_names, rounding_numbers,
|
579
|
+
"up05", "ROUND_05UP", DEC_ROUND_05UP );
|
580
|
+
// DEC_ROUND_DEFAULT is a macro with an extra ; so be careful
|
581
|
+
round = DEC_ROUND_DEFAULT;
|
582
|
+
round_default_num = INT2FIX(round);
|
583
|
+
rb_hash_aset( rounding_numbers, ID2SYM(rb_intern("default")), round_default_num );
|
584
|
+
rb_define_const( cDecContext, "ROUND_DEFAULT", round_default_num );
|
585
|
+
|
586
|
+
// *** methods
|
452
587
|
rb_define_alloc_func(cDecContext, con_alloc);
|
453
588
|
rb_define_method(cDecContext, "initialize", con_initialize, -1);
|
589
|
+
rb_define_method(cDecContext, "rounding", con_get_rounding, 0);
|
590
|
+
rb_define_method(cDecContext, "rounding=", con_set_rounding, 1);
|
591
|
+
rb_define_method(cDecContext, "digits", con_get_digits, 0);
|
592
|
+
rb_define_method(cDecContext, "digits=", con_set_digits, 1);
|
593
|
+
rb_define_method(cDecContext, "emin", con_get_emin, 0);
|
594
|
+
rb_define_method(cDecContext, "emin=", con_set_emin, 1);
|
595
|
+
rb_define_method(cDecContext, "emax", con_get_emax, 0);
|
596
|
+
rb_define_method(cDecContext, "emax=", con_set_emax, 1);
|
597
|
+
|
598
|
+
/****
|
599
|
+
DecNumber
|
600
|
+
****/
|
454
601
|
cDecNumber = rb_define_class("DecNumber", rb_cNumeric );
|
455
602
|
rb_define_alloc_func(cDecNumber, num_alloc);
|
603
|
+
rb_define_attr( cDecNumber, "context", 1, 1);
|
456
604
|
rb_define_method(cDecNumber, "initialize", num_initialize, -1);
|
457
605
|
rb_define_method(cDecNumber, "to_s", num_to_s, 0);
|
458
606
|
rb_define_method(cDecNumber, "to_i", num_to_i, 0);
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dec_number
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-11-
|
12
|
+
date: 2011-11-21 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Wrapper for ICU-decNumber library
|
15
15
|
email:
|