/
bignum.cpp
126 lines (95 loc) · 3.73 KB
/
bignum.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <math.h>
#include <cmath>
#include "builtin/bignum.hpp"
#include "builtin/object.hpp"
#include "capi/capi.hpp"
#include "capi/ruby.h"
using namespace rubinius;
using namespace rubinius::capi;
extern "C" {
VALUE rb_big2str(VALUE self, int base) {
return rb_funcall(self, rb_intern("to_s"), 1, INT2FIX(base));
}
long rb_big2long(VALUE obj) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
Object* object = env->get_object(obj);
if(object->nil_p()) {
rb_raise(rb_eTypeError, "no implicit conversion from nil to long");
} else if(Bignum* big = try_as<Bignum>(object)) {
if((size_t)mp_count_bits(big->mp_val()) > sizeof(long) * CHAR_BIT)
rb_raise(rb_eRangeError, "bignum too big to convert into long");
unsigned long val = big->to_ulong();
if((long)val < 0 && (big->mp_val()->sign == MP_ZPOS || (long)val != LONG_MIN))
rb_raise(rb_eRangeError, "bignum too big to convert into long");
if(big->mp_val()->sign == MP_NEG)
return -val;
return val;
}
rb_raise(rb_eArgError, "parameter is not a Bignum");
return 0;
}
unsigned long rb_big2ulong(VALUE obj) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
Object* object = env->get_object(obj);
if(object->nil_p()) {
rb_raise(rb_eTypeError, "no implicit conversion from nil to unsigned long");
} else if(Bignum* big = try_as<Bignum>(object)) {
if((size_t)mp_count_bits(big->mp_val()) > sizeof(long) * CHAR_BIT)
rb_raise(rb_eRangeError, "bignum too big to convert into long");
unsigned long val = big->to_ulong();
if(big->mp_val()->sign == MP_NEG) {
if((long)val < 0)
rb_raise(rb_eRangeError, "bignum out of range of unsigned long");
return -val;
}
return val;
}
rb_raise(rb_eArgError, "parameter is not a Bignum");
return 0;
}
long long rb_big2ll(VALUE obj) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
Object* object = env->get_object(obj);
if(object->nil_p()) {
rb_raise(rb_eTypeError, "no implicit conversion from nil to unsigned long");
} else if(Bignum* big = try_as<Bignum>(object)) {
if((size_t)mp_count_bits(big->mp_val()) > sizeof(long long) * CHAR_BIT)
rb_raise(rb_eRangeError, "bignum too big to convert into long long");
long long val = big->to_ulong_long();
if(big->mp_val()->sign == MP_NEG) return -val;
return val;
}
rb_raise(rb_eArgError, "parameter is not a Bignum");
return 0;
}
unsigned long long rb_big2ull(VALUE obj) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
Object* object = env->get_object(obj);
if(object->nil_p()) {
rb_raise(rb_eTypeError, "no implicit conversion from nil to unsigned long");
} else if(Bignum* big = try_as<Bignum>(object)) {
if((size_t)mp_count_bits(big->mp_val()) > sizeof(unsigned long long) * CHAR_BIT)
rb_raise(rb_eRangeError, "bignum too big to convert into unsigned long long");
unsigned long long val = big->to_ulong_long();
if(big->mp_val()->sign == MP_NEG) return -val;
return val;
}
rb_raise(rb_eArgError, "parameter is not a Bignum");
return 0;
}
double rb_big2dbl(VALUE obj) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
Bignum* big = c_as<Bignum>(env->get_object(obj));
double d = big->to_double(env->state());
if(std::isinf(d)) {
rb_warn("Bignum out of Float range");
d = HUGE_VAL;
}
return d;
}
int rb_big_bytes_used(VALUE obj) {
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
Bignum* big = c_as<Bignum>(env->get_object(obj));
return big->size(env->state())->to_native();
}
}