qr_reader-native 0.0.1
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.
- checksums.yaml +7 -0
- data/LICENSE-mruby.txt +22 -0
- data/LICENSE-spinel.txt +19 -0
- data/LICENSE.txt +21 -0
- data/README.md +61 -0
- data/ext/qr_reader_native/SPINEL_VERSION +1 -0
- data/ext/qr_reader_native/extconf.rb +8 -0
- data/ext/qr_reader_native/mruby/error.h +13 -0
- data/ext/qr_reader_native/mruby/internal.h +145 -0
- data/ext/qr_reader_native/mruby/string.h +22 -0
- data/ext/qr_reader_native/mruby.h +93 -0
- data/ext/qr_reader_native/mruby_shim.h +118 -0
- data/ext/qr_reader_native/qr_reader_native.c +13513 -0
- data/ext/qr_reader_native/qr_reader_native.h +29 -0
- data/ext/qr_reader_native/qr_reader_native_ext.c +598 -0
- data/ext/qr_reader_native/re_cased.h +71 -0
- data/ext/qr_reader_native/re_compile.c +5784 -0
- data/ext/qr_reader_native/re_ctype.h +3540 -0
- data/ext/qr_reader_native/re_exec.c +2190 -0
- data/ext/qr_reader_native/re_internal.h +671 -0
- data/ext/qr_reader_native/re_prop.h +4629 -0
- data/ext/qr_reader_native/re_spinel.c +363 -0
- data/ext/qr_reader_native/re_spinel.h +22 -0
- data/ext/qr_reader_native/re_spinel_utf8.inc +97 -0
- data/ext/qr_reader_native/re_utf8.c +156 -0
- data/ext/qr_reader_native/sp_alloc.c +1447 -0
- data/ext/qr_reader_native/sp_alloc.h +1196 -0
- data/ext/qr_reader_native/sp_argf.h +33 -0
- data/ext/qr_reader_native/sp_array.c +1052 -0
- data/ext/qr_reader_native/sp_array.h +456 -0
- data/ext/qr_reader_native/sp_bigint.c +5826 -0
- data/ext/qr_reader_native/sp_bigint.h +117 -0
- data/ext/qr_reader_native/sp_cold.c +5259 -0
- data/ext/qr_reader_native/sp_compat.h +402 -0
- data/ext/qr_reader_native/sp_core.c +818 -0
- data/ext/qr_reader_native/sp_core.h +56 -0
- data/ext/qr_reader_native/sp_crypto.c +877 -0
- data/ext/qr_reader_native/sp_crypto.h +169 -0
- data/ext/qr_reader_native/sp_dtoa.c +1533 -0
- data/ext/qr_reader_native/sp_dtoa.h +29 -0
- data/ext/qr_reader_native/sp_encoding_names.h +172 -0
- data/ext/qr_reader_native/sp_enum.h +86 -0
- data/ext/qr_reader_native/sp_exc.c +1185 -0
- data/ext/qr_reader_native/sp_exc.h +186 -0
- data/ext/qr_reader_native/sp_exc_ctx.h +56 -0
- data/ext/qr_reader_native/sp_fiber.c +889 -0
- data/ext/qr_reader_native/sp_fiber.h +162 -0
- data/ext/qr_reader_native/sp_fiber_ctx.h +84 -0
- data/ext/qr_reader_native/sp_format.c +695 -0
- data/ext/qr_reader_native/sp_format.h +83 -0
- data/ext/qr_reader_native/sp_gc.c +1793 -0
- data/ext/qr_reader_native/sp_gc.h +762 -0
- data/ext/qr_reader_native/sp_hash.c +131 -0
- data/ext/qr_reader_native/sp_hash.h +131 -0
- data/ext/qr_reader_native/sp_inspect.c +215 -0
- data/ext/qr_reader_native/sp_inspect.h +128 -0
- data/ext/qr_reader_native/sp_io.c +1676 -0
- data/ext/qr_reader_native/sp_io.h +272 -0
- data/ext/qr_reader_native/sp_iobuffer.c +1014 -0
- data/ext/qr_reader_native/sp_iobuffer.h +167 -0
- data/ext/qr_reader_native/sp_marshal.c +487 -0
- data/ext/qr_reader_native/sp_marshal.h +60 -0
- data/ext/qr_reader_native/sp_net.c +1029 -0
- data/ext/qr_reader_native/sp_net.h +205 -0
- data/ext/qr_reader_native/sp_pack.c +1254 -0
- data/ext/qr_reader_native/sp_poly_cold.c +1220 -0
- data/ext/qr_reader_native/sp_proc.c +410 -0
- data/ext/qr_reader_native/sp_proc.h +327 -0
- data/ext/qr_reader_native/sp_process.c +547 -0
- data/ext/qr_reader_native/sp_process_status.c +211 -0
- data/ext/qr_reader_native/sp_process_status.h +66 -0
- data/ext/qr_reader_native/sp_random.c +287 -0
- data/ext/qr_reader_native/sp_random.h +52 -0
- data/ext/qr_reader_native/sp_range.h +144 -0
- data/ext/qr_reader_native/sp_re.c +1379 -0
- data/ext/qr_reader_native/sp_re.h +186 -0
- data/ext/qr_reader_native/sp_re_names.h +59 -0
- data/ext/qr_reader_native/sp_sched.c +4044 -0
- data/ext/qr_reader_native/sp_sched.h +295 -0
- data/ext/qr_reader_native/sp_slab.c +1507 -0
- data/ext/qr_reader_native/sp_str.c +1462 -0
- data/ext/qr_reader_native/sp_str.h +306 -0
- data/ext/qr_reader_native/sp_str_crypt.c +23 -0
- data/ext/qr_reader_native/sp_string.c +92 -0
- data/ext/qr_reader_native/sp_string.h +253 -0
- data/ext/qr_reader_native/sp_system.c +78 -0
- data/ext/qr_reader_native/sp_system.h +18 -0
- data/ext/qr_reader_native/sp_time.c +860 -0
- data/ext/qr_reader_native/sp_time.h +100 -0
- data/ext/qr_reader_native/sp_types.h +292 -0
- data/ext/qr_reader_native/spinel_rt.h +19017 -0
- data/ext/qr_reader_native/unicase.c +399 -0
- data/ext/qr_reader_native/unicase.h +901 -0
- data/lib/qr_reader/native.rb +6 -0
- metadata +153 -0
|
@@ -0,0 +1,695 @@
|
|
|
1
|
+
/* sp_format.c -- cold value-type display helpers (see sp_format.h).
|
|
2
|
+
Self-contained: the shared value types (sp_types.h) + string allocator
|
|
3
|
+
(sp_alloc.h) + libc formatting, and sp_time.c's Time renderer. */
|
|
4
|
+
#include "sp_format.h"
|
|
5
|
+
#include "sp_alloc.h" /* sp_str_alloc_raw, sp_raise_cls, <math.h> for cos/sin/sqrt */
|
|
6
|
+
#include "sp_dtoa.h" /* sp_format_float (locale-independent %g) */
|
|
7
|
+
#include <stdio.h>
|
|
8
|
+
#include <string.h>
|
|
9
|
+
#include "sp_time.h" /* sp_time_inspect_v / sp_time_to_s_v */
|
|
10
|
+
#include "sp_range.h" /* sp_range_inspect */
|
|
11
|
+
|
|
12
|
+
/* Format a non-negative Complex-component magnitude the way MRI does: infinite
|
|
13
|
+
and NaN values become the Ruby names Infinity/NaN (not C's inf/nan), a
|
|
14
|
+
Float-classed component (is_f) renders Ruby-float style ("2.0"), a whole
|
|
15
|
+
Integer-classed value stays integer-looking, else %g. Returns the length. */
|
|
16
|
+
static int sp_complex_mag(char *out, size_t sz, sp_float v, int is_f) {SP_GC_ROOT_STR(out);
|
|
17
|
+
if (isinf(v)) return snprintf(out, sz, "Infinity");
|
|
18
|
+
if (isnan(v)) return snprintf(out, sz, "NaN");
|
|
19
|
+
if (is_f) return snprintf(out, sz, "%s", sp_float_to_s(v));
|
|
20
|
+
/* a float outside sp_int's range makes (sp_int)v undefined behavior; only
|
|
21
|
+
integer-print a whole value that fits, else fall through to %g. */
|
|
22
|
+
if (v >= -(sp_float)INTPTR_MAX && v <= (sp_float)INTPTR_MAX && v == (sp_int)v)
|
|
23
|
+
return snprintf(out, sz, "%lld", (long long)v);
|
|
24
|
+
{ char fb[32]; sp_format_float(v, fb, sizeof fb, 'g', -2, '\0'); return snprintf(out, sz, "%s", fb); }
|
|
25
|
+
}
|
|
26
|
+
/* Append the imaginary part ("+<mag>i" / "-<mag>i") to buf. MRI inserts a `*`
|
|
27
|
+
before a non-numeric magnitude (Infinity/NaN) so `Infinity*i` stays readable,
|
|
28
|
+
while a plain number is written as `10i`. */
|
|
29
|
+
static int sp_complex_imag(char *buf, int n, size_t sz, sp_float im, int is_f) {SP_GC_ROOT_STR(buf);
|
|
30
|
+
if (n < 0 || (size_t)n >= sz) return 0;
|
|
31
|
+
char mag[64];
|
|
32
|
+
sp_complex_mag(mag, sizeof mag, im < 0 ? -im : im, is_f);
|
|
33
|
+
const char *sep = (mag[0] >= '0' && mag[0] <= '9') ? "" : "*";
|
|
34
|
+
return snprintf(buf + n, sz - (size_t)n, "%c%s%si", im < 0 ? '-' : '+', mag, sep);
|
|
35
|
+
}
|
|
36
|
+
const char *sp_complex_inspect(sp_Complex c) {
|
|
37
|
+
char buf[128], re[64];
|
|
38
|
+
sp_complex_mag(re, sizeof re, c.re < 0 ? -c.re : c.re, c.fl & SP_CPLX_RE_F);
|
|
39
|
+
int n = snprintf(buf, sizeof buf, "(%s%s", c.re < 0 ? "-" : "", re);
|
|
40
|
+
if (n < 0) n = 0; else if (n >= (int)sizeof buf) n = (int)sizeof buf - 1;
|
|
41
|
+
n += sp_complex_imag(buf, n, sizeof buf, c.im, c.fl & SP_CPLX_IM_F);
|
|
42
|
+
if (n < (int)sizeof buf) n += snprintf(buf + n, sizeof(buf) - (size_t)n, ")");
|
|
43
|
+
if (n < 0) n = 0; else if (n >= (int)sizeof buf) n = (int)sizeof buf - 1;
|
|
44
|
+
char *r = sp_str_alloc_raw(n + 1);
|
|
45
|
+
memcpy(r, buf, n);
|
|
46
|
+
r[n] = 0;
|
|
47
|
+
return r;
|
|
48
|
+
}
|
|
49
|
+
/* Complex#to_s: bare `re+imi` (no surrounding parens, unlike #inspect). */
|
|
50
|
+
const char *sp_complex_to_s(sp_Complex c) {
|
|
51
|
+
char buf[128], re[64];
|
|
52
|
+
sp_complex_mag(re, sizeof re, c.re < 0 ? -c.re : c.re, c.fl & SP_CPLX_RE_F);
|
|
53
|
+
int n = snprintf(buf, sizeof buf, "%s%s", c.re < 0 ? "-" : "", re);
|
|
54
|
+
if (n < 0) n = 0; else if (n >= (int)sizeof buf) n = (int)sizeof buf - 1;
|
|
55
|
+
n += sp_complex_imag(buf, n, sizeof buf, c.im, c.fl & SP_CPLX_IM_F);
|
|
56
|
+
if (n < 0) n = 0; else if (n >= (int)sizeof buf) n = (int)sizeof buf - 1;
|
|
57
|
+
char *r = sp_str_alloc_raw(n + 1);
|
|
58
|
+
memcpy(r, buf, n);
|
|
59
|
+
r[n] = 0;
|
|
60
|
+
return r;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const char *sp_rational_inspect(sp_Rational r) {
|
|
64
|
+
char buf[64];
|
|
65
|
+
int n = snprintf(buf, sizeof(buf), "(%lld/%lld)", (long long)r.num, (long long)r.den);
|
|
66
|
+
if (n < 0) n = 0;
|
|
67
|
+
char *o = sp_str_alloc_raw(n + 1);
|
|
68
|
+
memcpy(o, buf, n);
|
|
69
|
+
o[n] = 0;
|
|
70
|
+
return o;
|
|
71
|
+
}
|
|
72
|
+
/* Rational#to_s: bare `num/den` (no parens, unlike #inspect). */
|
|
73
|
+
const char *sp_rational_to_s(sp_Rational r) {
|
|
74
|
+
char buf[64];
|
|
75
|
+
int n = snprintf(buf, sizeof(buf), "%lld/%lld", (long long)r.num, (long long)r.den);
|
|
76
|
+
if (n < 0) n = 0;
|
|
77
|
+
char *o = sp_str_alloc_raw(n + 1);
|
|
78
|
+
memcpy(o, buf, n);
|
|
79
|
+
o[n] = 0;
|
|
80
|
+
return o;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* A boxed Range renders as the typed one does: an open side is left out
|
|
84
|
+
("..3", "1.."), where the sentinel printed as -9223372036854775808. */
|
|
85
|
+
const char *sp_Range_inspect(sp_Range *r) {
|
|
86
|
+
return sp_range_inspect(*r);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* A boxed Time renders as an unboxed one does (lib/sp_time.c): its own
|
|
90
|
+
zone kind and offset, the year in Ruby's form. A gmtime + strftime
|
|
91
|
+
rendering here called every Time UTC, and C's %Y left a year below 1000
|
|
92
|
+
unpadded on glibc. */
|
|
93
|
+
const char *sp_Time_inspect(sp_Time *t) {SP_GC_ROOT(t); return sp_time_inspect_v(*t); }
|
|
94
|
+
const char *sp_Time_to_s(sp_Time *t) {SP_GC_ROOT(t); return sp_time_to_s_v(*t); }
|
|
95
|
+
|
|
96
|
+
/* ---- Complex arithmetic ---- */
|
|
97
|
+
/* Component-class (fl) propagation mirrors CRuby's numeric tower: add/sub act
|
|
98
|
+
per component, so each Float bit carries through independently; mul/div mix
|
|
99
|
+
all four components, so any Float input floats both results. */
|
|
100
|
+
/* Complex.polar: CRuby resolves an angle of exactly 0, pi/2, or pi without
|
|
101
|
+
cos/sin (the magnitude keeps its class, the other component is 0.0);
|
|
102
|
+
any other angle computes both components as Floats. m_is_f carries the
|
|
103
|
+
magnitude's static class from codegen. */
|
|
104
|
+
sp_Complex sp_complex_polar(sp_float m, sp_float a, int m_is_f) {
|
|
105
|
+
sp_Complex c;
|
|
106
|
+
int mf = m_is_f ? 1 : 0;
|
|
107
|
+
if (a == 0) { c.re = m; c.im = 0.0; c.fl = (unsigned char)((mf ? SP_CPLX_RE_F : 0) | SP_CPLX_IM_F); return c; }
|
|
108
|
+
if (a == M_PI_2) { c.re = 0.0; c.im = m; c.fl = (unsigned char)(SP_CPLX_RE_F | (mf ? SP_CPLX_IM_F : 0)); return c; }
|
|
109
|
+
if (a == M_PI) { c.re = -m; c.im = 0.0; c.fl = (unsigned char)((mf ? SP_CPLX_RE_F : 0) | SP_CPLX_IM_F); return c; }
|
|
110
|
+
c.re = m * cos(a); c.im = m * sin(a); c.fl = SP_CPLX_RE_F | SP_CPLX_IM_F;
|
|
111
|
+
return c;
|
|
112
|
+
}
|
|
113
|
+
sp_Complex sp_complex_add(sp_Complex a, sp_Complex b) { sp_Complex c; c.re = a.re + b.re; c.im = a.im + b.im; c.fl = a.fl | b.fl; return c; }
|
|
114
|
+
sp_Complex sp_complex_mul(sp_Complex a, sp_Complex b) { sp_Complex c; c.re = (a.re * b.re) - (a.im * b.im); c.im = (a.re * b.im) + (a.im * b.re); c.fl = (a.fl | b.fl) ? (SP_CPLX_RE_F | SP_CPLX_IM_F) : 0; return c; }
|
|
115
|
+
sp_Complex sp_complex_conjugate(sp_Complex a) { sp_Complex c; c.re = a.re; c.im = -a.im; c.fl = a.fl; return c; }
|
|
116
|
+
sp_Complex sp_complex_sub(sp_Complex a, sp_Complex b) { sp_Complex c; c.re = a.re - b.re; c.im = a.im - b.im; c.fl = a.fl | b.fl; return c; }
|
|
117
|
+
sp_Complex sp_complex_div(sp_Complex a, sp_Complex b) {
|
|
118
|
+
sp_float d = (b.re * b.re) + (b.im * b.im); sp_Complex c;
|
|
119
|
+
c.re = ((a.re * b.re) + (a.im * b.im)) / d; c.im = ((a.im * b.re) - (a.re * b.im)) / d;
|
|
120
|
+
c.fl = (a.fl | b.fl) ? (SP_CPLX_RE_F | SP_CPLX_IM_F) : 0;
|
|
121
|
+
return c;
|
|
122
|
+
}
|
|
123
|
+
/* Complex divided by a real scalar divides each component -- unlike the
|
|
124
|
+
conjugate formula, this yields Infinity (not NaN) when the divisor is 0.0,
|
|
125
|
+
matching MRI's Complex#/ against a Float. */
|
|
126
|
+
sp_Complex sp_complex_div_real(sp_Complex a, sp_float b) {
|
|
127
|
+
sp_Complex c; c.re = a.re / b; c.im = a.im / b; c.fl = SP_CPLX_RE_F | SP_CPLX_IM_F; return c;
|
|
128
|
+
}
|
|
129
|
+
/* Complex divided by an Integer follows integer zero-division rules: dividing
|
|
130
|
+
by 0 raises ZeroDivisionError, as in MRI (a Float divisor gives Infinity). */
|
|
131
|
+
sp_Complex sp_complex_div_int(sp_Complex a, sp_int b) {
|
|
132
|
+
if (b == 0) sp_raise_cls("ZeroDivisionError", "divided by 0");
|
|
133
|
+
sp_Complex c; c.re = a.re / (sp_float)b; c.im = a.im / (sp_float)b; c.fl = a.fl; return c;
|
|
134
|
+
}
|
|
135
|
+
sp_Complex sp_complex_neg(sp_Complex a) { sp_Complex c; c.re = -a.re; c.im = -a.im; c.fl = a.fl; return c; }
|
|
136
|
+
sp_float sp_complex_abs2(sp_Complex a) { return (a.re * a.re) + (a.im * a.im); }
|
|
137
|
+
sp_float sp_complex_abs(sp_Complex a) { return sqrt((a.re * a.re) + (a.im * a.im)); }
|
|
138
|
+
sp_bool sp_complex_eq(sp_Complex a, sp_Complex b) { return a.re == b.re && a.im == b.im; }
|
|
139
|
+
/* z ** w for a non-integer exponent: exp(w * ln z); an integral real w
|
|
140
|
+
defers to the exact integer power (preserving component classes). */
|
|
141
|
+
sp_Complex sp_complex_pow_c(sp_Complex z, sp_Complex w) {
|
|
142
|
+
if (w.im == 0.0 && w.re == (sp_float)(sp_int)w.re && !(w.fl & SP_CPLX_RE_F))
|
|
143
|
+
return sp_complex_pow(z, (sp_int)w.re);
|
|
144
|
+
sp_float lr = 0.5 * log(z.re * z.re + z.im * z.im);
|
|
145
|
+
sp_float th = atan2(z.im, z.re);
|
|
146
|
+
sp_float xa = w.re * lr - w.im * th;
|
|
147
|
+
sp_float xb = w.re * th + w.im * lr;
|
|
148
|
+
sp_float m = exp(xa);
|
|
149
|
+
sp_Complex r;
|
|
150
|
+
r.re = m * cos(xb);
|
|
151
|
+
r.im = m * sin(xb);
|
|
152
|
+
r.fl = SP_CPLX_RE_F | SP_CPLX_IM_F;
|
|
153
|
+
return r;
|
|
154
|
+
}
|
|
155
|
+
sp_Complex sp_complex_pow(sp_Complex a, sp_int e) {
|
|
156
|
+
if (e < 0 && a.re == 0.0 && a.im == 0.0)
|
|
157
|
+
sp_raise_cls("ZeroDivisionError", "divided by 0"); /* (#2965) */
|
|
158
|
+
sp_Complex r; r.re = 1; r.im = 0; r.fl = 0;
|
|
159
|
+
sp_int k = e < 0 ? -e : e;
|
|
160
|
+
for (sp_int i = 0; i < k; i++) r = sp_complex_mul(r, a);
|
|
161
|
+
if (e < 0) { sp_Complex one; one.re = 1; one.im = 0; one.fl = 0; r = sp_complex_div(one, r); }
|
|
162
|
+
return r;
|
|
163
|
+
}
|
|
164
|
+
/* Complex ** Rational: a whole-number exponent (den 1) stays exact via the
|
|
165
|
+
integer power; a fractional exponent computes in floats. (#2962) */
|
|
166
|
+
sp_Complex sp_complex_pow_rational(sp_Complex z, sp_Rational w) {
|
|
167
|
+
if (w.den == 1) return sp_complex_pow(z, w.num);
|
|
168
|
+
return sp_complex_pow_c(z, (sp_Complex){sp_rational_to_f(w), 0, SP_CPLX_RE_F | SP_CPLX_IM_F});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* ---- Rational arithmetic ----
|
|
172
|
+
Intermediate products use a wider type; a result that does not fit back into
|
|
173
|
+
sp_int raises RangeError (mruby promotes to Bigint -- a later phase can too).
|
|
174
|
+
A 128-bit integer covers the 64-bit build (see sp_rat_wide below); int64 covers two int32 operands losslessly. */
|
|
175
|
+
static sp_int sp_rational_gcd_i(sp_int a, sp_int b) {
|
|
176
|
+
if (a < 0) a = -a;
|
|
177
|
+
if (b < 0) b = -b;
|
|
178
|
+
while (b) { sp_int t = b; b = a % b; a = t; }
|
|
179
|
+
return a;
|
|
180
|
+
}
|
|
181
|
+
sp_Rational sp_rational_new(sp_int n, sp_int d) {
|
|
182
|
+
sp_Rational r;
|
|
183
|
+
if (d == 0) { r.num = n; r.den = 0; return r; }
|
|
184
|
+
if (d < 0) { n = -n; d = -d; }
|
|
185
|
+
sp_int g = sp_rational_gcd_i(n, d);
|
|
186
|
+
if (g <= 0) g = 1;
|
|
187
|
+
r.num = n / g;
|
|
188
|
+
r.den = d / g;
|
|
189
|
+
return r;
|
|
190
|
+
}
|
|
191
|
+
/* Kernel#Rational(String): unlike String#to_r, the whole string must be a
|
|
192
|
+
rational literal -- trailing text, an empty string and a second `/` are all
|
|
193
|
+
ArgumentError, and an exponent is honoured (#3720). */
|
|
194
|
+
sp_Rational sp_str_to_r_strict(const char *s) {SP_GC_ROOT_STR(s);
|
|
195
|
+
const char *p = s;
|
|
196
|
+
if (!p) sp_raise_cls("TypeError", "can't convert nil into Rational");
|
|
197
|
+
while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == '\f' || *p == '\v') p++;
|
|
198
|
+
sp_int sign = 1;
|
|
199
|
+
if (*p == '+') p++;
|
|
200
|
+
else if (*p == '-') { sign = -1; p++; }
|
|
201
|
+
sp_int num = 0, den = 1;
|
|
202
|
+
int any = 0;
|
|
203
|
+
while ((*p >= '0' && *p <= '9') || *p == '_') { if (*p != '_') { num = num * 10 + (*p - '0'); any = 1; } p++; }
|
|
204
|
+
if (*p == '.') {
|
|
205
|
+
p++;
|
|
206
|
+
while ((*p >= '0' && *p <= '9') || *p == '_') { if (*p != '_') { num = num * 10 + (*p - '0'); den *= 10; any = 1; } p++; }
|
|
207
|
+
}
|
|
208
|
+
if (!any) {
|
|
209
|
+
if (sp_convert_soft) { sp_convert_failed = 1; return sp_rational_new(0, 1); }
|
|
210
|
+
sp_raise_cls("ArgumentError", sp_sprintf("invalid value for Rational(): \"%s\"", s));
|
|
211
|
+
}
|
|
212
|
+
if (*p == 'e' || *p == 'E') {
|
|
213
|
+
const char *q = p + 1;
|
|
214
|
+
sp_int esign = 1;
|
|
215
|
+
if (*q == '+') q++; else if (*q == '-') { esign = -1; q++; }
|
|
216
|
+
sp_int ev = 0; int anye = 0;
|
|
217
|
+
while (*q >= '0' && *q <= '9') { ev = ev * 10 + (*q - '0'); q++; anye = 1; }
|
|
218
|
+
if (anye) {
|
|
219
|
+
for (sp_int k = 0; k < ev; k++) { if (esign > 0) num *= 10; else den *= 10; }
|
|
220
|
+
p = q;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (*p == '/') {
|
|
224
|
+
p++;
|
|
225
|
+
sp_int d2 = 0; int anyd = 0;
|
|
226
|
+
while ((*p >= '0' && *p <= '9') || *p == '_') { if (*p != '_') { d2 = d2 * 10 + (*p - '0'); anyd = 1; } p++; }
|
|
227
|
+
if (!anyd) sp_raise_cls("ArgumentError", sp_sprintf("invalid value for Rational(): \"%s\"", s));
|
|
228
|
+
if (d2 == 0) sp_raise_cls("ZeroDivisionError", "divided by 0");
|
|
229
|
+
den *= d2;
|
|
230
|
+
}
|
|
231
|
+
while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == '\f' || *p == '\v') p++;
|
|
232
|
+
if (*p) sp_raise_cls("ArgumentError", sp_sprintf("invalid value for Rational(): \"%s\"", s));
|
|
233
|
+
return sp_rational_new(sign * num, den);
|
|
234
|
+
}
|
|
235
|
+
/* The products of two sp_int fit a 128-bit integer on the 64-bit build and a
|
|
236
|
+
long long on the 32-bit one. A 64-bit build without a 128-bit type
|
|
237
|
+
(sp_compat.h) computes in long long and checks every step, raising the
|
|
238
|
+
RangeError an out-of-range result raises anyway -- earlier than the wide
|
|
239
|
+
type would, for an intermediate the reduction would have brought back. */
|
|
240
|
+
#if INTPTR_MAX > 0x7fffffff && SP_HAVE_INT128
|
|
241
|
+
typedef sp_int128 sp_rat_wide;
|
|
242
|
+
# define SP_RAT_MUL(a, b) ((sp_rat_wide)(a) * (b))
|
|
243
|
+
# define SP_RAT_ADD(a, b) ((a) + (b))
|
|
244
|
+
# define SP_RAT_SUB(a, b) ((a) - (b))
|
|
245
|
+
#elif INTPTR_MAX > 0x7fffffff
|
|
246
|
+
typedef long long sp_rat_wide;
|
|
247
|
+
static void sp_rat_ovf(void) { sp_raise_cls("RangeError", "Rational out of sp_int range"); }
|
|
248
|
+
static sp_rat_wide sp_rat_mul_ck(sp_rat_wide a, sp_rat_wide b) {
|
|
249
|
+
intptr_t r; if (sp_ckd_mul_iptr((intptr_t)a, (intptr_t)b, &r)) sp_rat_ovf(); return r;
|
|
250
|
+
}
|
|
251
|
+
static sp_rat_wide sp_rat_add_ck(sp_rat_wide a, sp_rat_wide b) {
|
|
252
|
+
intptr_t r; if (sp_ckd_add_iptr((intptr_t)a, (intptr_t)b, &r)) sp_rat_ovf(); return r;
|
|
253
|
+
}
|
|
254
|
+
static sp_rat_wide sp_rat_sub_ck(sp_rat_wide a, sp_rat_wide b) {
|
|
255
|
+
intptr_t r; if (sp_ckd_sub_iptr((intptr_t)a, (intptr_t)b, &r)) sp_rat_ovf(); return r;
|
|
256
|
+
}
|
|
257
|
+
# define SP_RAT_MUL(a, b) sp_rat_mul_ck((sp_rat_wide)(a), (sp_rat_wide)(b))
|
|
258
|
+
# define SP_RAT_ADD(a, b) sp_rat_add_ck(a, b)
|
|
259
|
+
# define SP_RAT_SUB(a, b) sp_rat_sub_ck(a, b)
|
|
260
|
+
#else
|
|
261
|
+
typedef long long sp_rat_wide;
|
|
262
|
+
# define SP_RAT_MUL(a, b) ((sp_rat_wide)(a) * (b))
|
|
263
|
+
# define SP_RAT_ADD(a, b) ((a) + (b))
|
|
264
|
+
# define SP_RAT_SUB(a, b) ((a) - (b))
|
|
265
|
+
#endif
|
|
266
|
+
static sp_int sp_rat_fit(sp_rat_wide v) {
|
|
267
|
+
if (v > (sp_rat_wide)INTPTR_MAX || v < (sp_rat_wide)(-INTPTR_MAX))
|
|
268
|
+
sp_raise_cls("RangeError", "Rational out of sp_int range");
|
|
269
|
+
return (sp_int)v;
|
|
270
|
+
}
|
|
271
|
+
/* A rational from a 64-bit numerator and denominator, reduced before it is
|
|
272
|
+
narrowed: Time#to_r's nanoseconds do not fit a 32-bit sp_int, its seconds
|
|
273
|
+
do (1577923200/1), and only a value that stays too wide after the
|
|
274
|
+
reduction raises. */
|
|
275
|
+
sp_Rational sp_rational_new_i64(int64_t n, int64_t d);
|
|
276
|
+
static sp_Rational sp_rational_new_wide(sp_rat_wide n, sp_rat_wide d) {
|
|
277
|
+
if (d == 0) sp_raise_cls("ZeroDivisionError", "divided by 0");
|
|
278
|
+
if (d < 0) { n = -n; d = -d; }
|
|
279
|
+
sp_rat_wide a = n < 0 ? -n : n, b = d;
|
|
280
|
+
while (b) { sp_rat_wide t = b; b = a % b; a = t; }
|
|
281
|
+
if (a <= 0) a = 1;
|
|
282
|
+
sp_Rational r;
|
|
283
|
+
r.num = sp_rat_fit(n / a);
|
|
284
|
+
r.den = sp_rat_fit(d / a);
|
|
285
|
+
return r;
|
|
286
|
+
}
|
|
287
|
+
sp_Rational sp_rational_new_i64(int64_t n, int64_t d) { return sp_rational_new_wide((sp_rat_wide)n, (sp_rat_wide)d); }
|
|
288
|
+
/* ---- String#to_r ----
|
|
289
|
+
A number is read as CRuby's read_num reads it: digits, an optional `.` and
|
|
290
|
+
digits, an optional exponent (`e`, a sign, digits), a single `_` allowed
|
|
291
|
+
between two digits (and after the zeros that begin a run); a `.` with no
|
|
292
|
+
digit after it is consumed, and so are an `e` and its sign with no digit
|
|
293
|
+
after them. The text is [ws][sign]number[/number]; it stops at the first
|
|
294
|
+
byte that fits nothing, and an unparseable String is 0/1.
|
|
295
|
+
|
|
296
|
+
A number is kept as a magnitude m in the wide type and a power of ten e,
|
|
297
|
+
the trailing zeros of its digits counted into e rather than multiplied in,
|
|
298
|
+
so 1.000000000000000000000 and 1000000000000000000000e-21 are 1. The two
|
|
299
|
+
sides meet as (m1/m2) * 10^(e1 - e2) with the gcd of the magnitudes taken
|
|
300
|
+
first and the powers of 2 and 5 of the ten cancelled against the side they
|
|
301
|
+
divide, so 5e40/1e40 is 5 and 5e-19 is 1/(2*10^18). A magnitude past the
|
|
302
|
+
wide type, an exponent past a quarter of it and a result that does not fit
|
|
303
|
+
64 bits are a RangeError (CRuby answers a Bignum Rational or a Float, or
|
|
304
|
+
raises for an exponent it cannot use), raised unless the other side is
|
|
305
|
+
zero: 0/<huge> is 0/1 and <huge>/0 is a ZeroDivisionError. */
|
|
306
|
+
#define SP_RATW_TOP ((sp_rat_wide)1 << (sizeof(sp_rat_wide) * 8 - 2))
|
|
307
|
+
#define SP_RATW_MAX (SP_RATW_TOP - 1 + SP_RATW_TOP)
|
|
308
|
+
typedef struct { sp_rat_wide m; sp_rat_wide e; int ovf; } sp_str_to_r_q;
|
|
309
|
+
static sp_rat_wide sp_str_to_r_step(sp_rat_wide m, sp_int add, sp_int mul, int *ovf) {
|
|
310
|
+
if (*ovf) return m;
|
|
311
|
+
if (m > (SP_RATW_MAX - add) / mul) { *ovf = 1; return m; }
|
|
312
|
+
return m * mul + add;
|
|
313
|
+
}
|
|
314
|
+
static sp_rat_wide sp_str_to_r_gcd(sp_rat_wide a, sp_rat_wide b) {
|
|
315
|
+
while (b) { sp_rat_wide t = a % b; a = b; b = t; }
|
|
316
|
+
return a;
|
|
317
|
+
}
|
|
318
|
+
/* a run of digits into the magnitude *m, trailing zeros held back in *z */
|
|
319
|
+
static const char *sp_str_to_r_run(const char *p, sp_rat_wide *m, sp_int *z, sp_int *nd, int *ovf) {
|
|
320
|
+
if (*p == '0') {
|
|
321
|
+
/* the zeros that begin a run, and a `_` between them, are read together
|
|
322
|
+
(CRuby squeezes them at the start of the integer, the fraction and the
|
|
323
|
+
exponent alike) */
|
|
324
|
+
int us = 0;
|
|
325
|
+
while (*p == '0' || *p == '_') {
|
|
326
|
+
if (*p == '_') {
|
|
327
|
+
if (++us >= 2) break;
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
us = 0;
|
|
331
|
+
(*nd)++;
|
|
332
|
+
if (*m != 0) (*z)++;
|
|
333
|
+
}
|
|
334
|
+
p++;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
while (*p >= '0' && *p <= '9') {
|
|
338
|
+
sp_int d = (sp_int)(*p - '0');
|
|
339
|
+
if (d == 0) {
|
|
340
|
+
if (*m != 0) (*z)++;
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
for (; *z > 0 && !*ovf; (*z)--) *m = sp_str_to_r_step(*m, 0, 10, ovf);
|
|
344
|
+
*z = 0;
|
|
345
|
+
*m = sp_str_to_r_step(*m, d, 10, ovf);
|
|
346
|
+
}
|
|
347
|
+
(*nd)++; p++;
|
|
348
|
+
if (*p == '_' && p[1] >= '0' && p[1] <= '9') p++;
|
|
349
|
+
}
|
|
350
|
+
return p;
|
|
351
|
+
}
|
|
352
|
+
static int sp_str_to_r_number(const char **pp, sp_str_to_r_q *q) {
|
|
353
|
+
const char *p = *pp;
|
|
354
|
+
sp_rat_wide m = 0;
|
|
355
|
+
sp_int z = 0, nd = 0, fd = 0;
|
|
356
|
+
sp_rat_wide e = 0;
|
|
357
|
+
int ovf = 0, eneg = 0, ehuge = 0;
|
|
358
|
+
if (*p != '.') {
|
|
359
|
+
p = sp_str_to_r_run(p, &m, &z, &nd, &ovf);
|
|
360
|
+
if (!nd) return 0;
|
|
361
|
+
}
|
|
362
|
+
if (*p == '.') {
|
|
363
|
+
p++;
|
|
364
|
+
p = sp_str_to_r_run(p, &m, &z, &fd, &ovf);
|
|
365
|
+
if (!fd) goto scaled;
|
|
366
|
+
}
|
|
367
|
+
if ((*p == 'e' || *p == 'E') && p[1]) {
|
|
368
|
+
p++;
|
|
369
|
+
if (*p == '+') p++;
|
|
370
|
+
else if (*p == '-') { eneg = 1; p++; }
|
|
371
|
+
sp_rat_wide ev = 0;
|
|
372
|
+
sp_int ez = 0, ed = 0;
|
|
373
|
+
int eovf = 0;
|
|
374
|
+
const char *t = sp_str_to_r_run(p, &ev, &ez, &ed, &eovf);
|
|
375
|
+
if (ed) {
|
|
376
|
+
p = t;
|
|
377
|
+
for (; ez > 0 && !eovf; ez--) ev = sp_str_to_r_step(ev, 0, 10, &eovf);
|
|
378
|
+
if (eovf || ev > (SP_RATW_TOP >> 1)) {
|
|
379
|
+
ehuge = 1;
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
e = ev;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
scaled:
|
|
387
|
+
*pp = p;
|
|
388
|
+
q->m = 0; q->e = 0; q->ovf = 0;
|
|
389
|
+
if (m == 0 && !ovf) return 1;
|
|
390
|
+
if (ovf || ehuge) { q->ovf = 1; return 1; }
|
|
391
|
+
q->m = m;
|
|
392
|
+
q->e = (sp_rat_wide)z - fd + (eneg ? -e : e);
|
|
393
|
+
return 1;
|
|
394
|
+
}
|
|
395
|
+
sp_Rational sp_str_to_r(const char *s) {SP_GC_ROOT_STR(s);
|
|
396
|
+
if (!s) return sp_rational_new(0, 1);
|
|
397
|
+
const char *p = s;
|
|
398
|
+
while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == '\f' || *p == '\v') p++;
|
|
399
|
+
int neg = 0;
|
|
400
|
+
if (*p == '+') p++;
|
|
401
|
+
else if (*p == '-') { neg = 1; p++; }
|
|
402
|
+
sp_str_to_r_q a, b;
|
|
403
|
+
int hb = 0;
|
|
404
|
+
if (!sp_str_to_r_number(&p, &a)) return sp_rational_new(0, 1);
|
|
405
|
+
if (*p == '/') { const char *t = p + 1; hb = sp_str_to_r_number(&t, &b); }
|
|
406
|
+
if (hb && !b.ovf && b.m == 0) sp_raise_cls("ZeroDivisionError", "divided by 0");
|
|
407
|
+
if (!a.ovf && a.m == 0) return sp_rational_new(0, 1);
|
|
408
|
+
if (a.ovf || (hb && b.ovf)) sp_raise_cls("RangeError", "Rational out of sp_int range");
|
|
409
|
+
sp_rat_wide n = a.m, d = 1;
|
|
410
|
+
sp_rat_wide k = a.e;
|
|
411
|
+
if (hb) {
|
|
412
|
+
sp_rat_wide g = sp_str_to_r_gcd(n, b.m);
|
|
413
|
+
n /= g;
|
|
414
|
+
d = b.m / g;
|
|
415
|
+
k -= b.e;
|
|
416
|
+
}
|
|
417
|
+
int ovf = 0;
|
|
418
|
+
sp_rat_wide c2 = 0, c5 = 0;
|
|
419
|
+
if (k >= 0) {
|
|
420
|
+
while (c2 < k && d % 2 == 0) { d /= 2; c2++; }
|
|
421
|
+
while (c5 < k && d % 5 == 0) { d /= 5; c5++; }
|
|
422
|
+
for (sp_rat_wide i = c2; i < k && !ovf; i++) n = sp_str_to_r_step(n, 0, 2, &ovf);
|
|
423
|
+
for (sp_rat_wide i = c5; i < k && !ovf; i++) n = sp_str_to_r_step(n, 0, 5, &ovf);
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
sp_rat_wide kk = -k;
|
|
427
|
+
while (c2 < kk && n % 2 == 0) { n /= 2; c2++; }
|
|
428
|
+
while (c5 < kk && n % 5 == 0) { n /= 5; c5++; }
|
|
429
|
+
for (sp_rat_wide i = c2; i < kk && !ovf; i++) d = sp_str_to_r_step(d, 0, 2, &ovf);
|
|
430
|
+
for (sp_rat_wide i = c5; i < kk && !ovf; i++) d = sp_str_to_r_step(d, 0, 5, &ovf);
|
|
431
|
+
}
|
|
432
|
+
if (ovf) sp_raise_cls("RangeError", "Rational out of sp_int range");
|
|
433
|
+
/* -INTPTR_MAX - 1 fits sp_int but not sp_rat_fit's symmetric range */
|
|
434
|
+
sp_Rational r;
|
|
435
|
+
if (sizeof(sp_rat_wide) > sizeof(sp_int) && neg && n - 1 == (sp_rat_wide)INTPTR_MAX) {
|
|
436
|
+
if (d > (sp_rat_wide)INTPTR_MAX) sp_raise_cls("RangeError", "Rational out of sp_int range");
|
|
437
|
+
r.num = (sp_int)(-INTPTR_MAX - 1); r.den = (sp_int)d;
|
|
438
|
+
return r;
|
|
439
|
+
}
|
|
440
|
+
if (n > (sp_rat_wide)INTPTR_MAX || d > (sp_rat_wide)INTPTR_MAX) sp_raise_cls("RangeError", "Rational out of sp_int range");
|
|
441
|
+
r.num = neg ? -(sp_int)n : (sp_int)n; r.den = (sp_int)d;
|
|
442
|
+
return r;
|
|
443
|
+
}
|
|
444
|
+
sp_Rational sp_rational_add(sp_Rational a, sp_Rational b) {
|
|
445
|
+
return sp_rational_new_wide(SP_RAT_ADD(SP_RAT_MUL(a.num, b.den), SP_RAT_MUL(b.num, a.den)),
|
|
446
|
+
SP_RAT_MUL(a.den, b.den));
|
|
447
|
+
}
|
|
448
|
+
sp_Rational sp_rational_sub(sp_Rational a, sp_Rational b) {
|
|
449
|
+
return sp_rational_new_wide(SP_RAT_SUB(SP_RAT_MUL(a.num, b.den), SP_RAT_MUL(b.num, a.den)),
|
|
450
|
+
SP_RAT_MUL(a.den, b.den));
|
|
451
|
+
}
|
|
452
|
+
sp_Rational sp_rational_mul(sp_Rational a, sp_Rational b) {
|
|
453
|
+
return sp_rational_new_wide(SP_RAT_MUL(a.num, b.num), SP_RAT_MUL(a.den, b.den));
|
|
454
|
+
}
|
|
455
|
+
sp_Rational sp_rational_div(sp_Rational a, sp_Rational b) {
|
|
456
|
+
if (b.num == 0) sp_raise_cls("ZeroDivisionError", "divided by 0");
|
|
457
|
+
return sp_rational_new_wide(SP_RAT_MUL(a.num, b.den), SP_RAT_MUL(a.den, b.num));
|
|
458
|
+
}
|
|
459
|
+
sp_Rational sp_rational_neg(sp_Rational a) { a.num = -a.num; return a; }
|
|
460
|
+
sp_Rational sp_rational_abs(sp_Rational a) { if (a.num < 0) a.num = -a.num; return a; }
|
|
461
|
+
sp_int sp_rational_cmp(sp_Rational a, sp_Rational b) {
|
|
462
|
+
sp_rat_wide l = SP_RAT_MUL(a.num, b.den), r = SP_RAT_MUL(b.num, a.den);
|
|
463
|
+
return l < r ? -1 : (l > r ? 1 : 0);
|
|
464
|
+
}
|
|
465
|
+
sp_bool sp_rational_eq(sp_Rational a, sp_Rational b) {
|
|
466
|
+
return a.num == b.num && a.den == b.den;
|
|
467
|
+
}
|
|
468
|
+
sp_float sp_rational_to_f(sp_Rational a) {
|
|
469
|
+
return (sp_float)a.num / (sp_float)a.den;
|
|
470
|
+
}
|
|
471
|
+
/* 2^e as a wide integer, raising RangeError past the sp_int range. */
|
|
472
|
+
static sp_rat_wide sp_rat_pow2(int e) {
|
|
473
|
+
sp_rat_wide r = 1;
|
|
474
|
+
for (int i = 0; i < e; i++) {
|
|
475
|
+
r <<= 1;
|
|
476
|
+
if (r > (sp_rat_wide)INTPTR_MAX) sp_raise_cls("RangeError", "Rational out of sp_int range");
|
|
477
|
+
}
|
|
478
|
+
return r;
|
|
479
|
+
}
|
|
480
|
+
/* Float#to_r : the exact rational value of the double. A finite double equals
|
|
481
|
+
m * 2^e for a 53-bit integer mantissa m, so the conversion is exact. When the
|
|
482
|
+
exact numerator/denominator does not fit in sp_int (huge magnitude or a tiny
|
|
483
|
+
subnormal), it raises RangeError -- spinel's Rational is int64/int64 and does
|
|
484
|
+
not promote to a Bignum (matching the existing Rational-overflow behavior). */
|
|
485
|
+
sp_Rational sp_float_to_rational(sp_float f) {
|
|
486
|
+
if (isnan(f) || isinf(f)) sp_raise_cls("FloatDomainError", isnan(f) ? "NaN" : "Infinity");
|
|
487
|
+
if (f == 0.0) { sp_Rational z; z.num = 0; z.den = 1; return z; }
|
|
488
|
+
int e;
|
|
489
|
+
double m = frexp((double)f, &e); /* f = m * 2^e, 0.5 <= |m| < 1 */
|
|
490
|
+
for (int i = 0; i < 53 && m != floor(m); i++) { m *= 2.0; e--; }
|
|
491
|
+
sp_rat_wide num = (sp_rat_wide)m; /* integer mantissa (fits in 54 bits) */
|
|
492
|
+
if (e >= 0) {
|
|
493
|
+
/* num * 2^e can exceed sp_rat_wide on a 32-bit build (long long); guard the
|
|
494
|
+
product first. p > INTPTR_MAX/|num| is exactly "num*p won't fit sp_int",
|
|
495
|
+
so this raises rather than overflowing. */
|
|
496
|
+
sp_rat_wide p = sp_rat_pow2(e), an = num < 0 ? -num : num;
|
|
497
|
+
if (an != 0 && p > (sp_rat_wide)INTPTR_MAX / an)
|
|
498
|
+
sp_raise_cls("RangeError", "Rational out of sp_int range");
|
|
499
|
+
return sp_rational_new_wide(num * p, 1);
|
|
500
|
+
}
|
|
501
|
+
return sp_rational_new_wide(num, sp_rat_pow2(-e));
|
|
502
|
+
}
|
|
503
|
+
/* Simplest p/q with lo <= p/q <= hi, for 0 < lo <= hi. Classic continued-fraction
|
|
504
|
+
"simplest rational in an interval" recursion; the convergent depth is bounded by
|
|
505
|
+
the interval, so q stays small for sane epsilons. */
|
|
506
|
+
static void sp_simplest_pos(double lo, double hi, sp_rat_wide *np, sp_rat_wide *dp) {
|
|
507
|
+
double fl = floor(lo);
|
|
508
|
+
if (fl == lo) { *np = (sp_rat_wide)fl; *dp = 1; return; } /* lo is an integer */
|
|
509
|
+
if (fl == floor(hi)) { /* no integer in (lo,hi) */
|
|
510
|
+
sp_rat_wide n, d;
|
|
511
|
+
sp_simplest_pos(1.0 / (hi - fl), 1.0 / (lo - fl), &n, &d);
|
|
512
|
+
*np = SP_RAT_ADD(SP_RAT_MUL(fl, n), d);
|
|
513
|
+
*dp = n;
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
*np = (sp_rat_wide)fl + 1; *dp = 1; /* fl+1 lies in [lo,hi] */
|
|
517
|
+
}
|
|
518
|
+
static sp_Rational sp_rationalize_interval(double lo, double hi) {
|
|
519
|
+
if (lo > hi) { double t = lo; lo = hi; hi = t; }
|
|
520
|
+
if (lo <= 0.0 && hi >= 0.0) { sp_Rational z; z.num = 0; z.den = 1; return z; }
|
|
521
|
+
int neg = 0;
|
|
522
|
+
if (hi < 0.0) { double t = -lo; lo = -hi; hi = t; neg = 1; } /* fold to positives */
|
|
523
|
+
/* Any p/q in [lo,hi] has p >= lo*q >= lo, so lo past sp_int can't fit and
|
|
524
|
+
floor(lo) would also overflow the (double->sp_rat_wide) cast below. */
|
|
525
|
+
if (lo > (double)INTPTR_MAX) sp_raise_cls("RangeError", "Rational out of sp_int range");
|
|
526
|
+
sp_rat_wide n, d;
|
|
527
|
+
sp_simplest_pos(lo, hi, &n, &d);
|
|
528
|
+
if (neg) n = -n;
|
|
529
|
+
return sp_rational_new_wide(n, d);
|
|
530
|
+
}
|
|
531
|
+
sp_Rational sp_float_rationalize(sp_float f, sp_float eps) {
|
|
532
|
+
if (isnan(f) || isinf(f)) sp_raise_cls("FloatDomainError", isnan(f) ? "NaN" : "Infinity");
|
|
533
|
+
double e = eps < 0 ? -eps : eps;
|
|
534
|
+
return sp_rationalize_interval((double)f - e, (double)f + e);
|
|
535
|
+
}
|
|
536
|
+
/* No-arg rationalize: simplest rational that round-trips to this exact double,
|
|
537
|
+
i.e. lying in the half-ulp interval around f. */
|
|
538
|
+
/* No-arg rationalize: the simplest rational whose nearest double is exactly f.
|
|
539
|
+
The continued-fraction convergents of f are, by construction, the simplest
|
|
540
|
+
rationals approximating it in increasing complexity, so the FIRST convergent
|
|
541
|
+
that round-trips to f is the answer. This is robust where a double-precision
|
|
542
|
+
half-ulp interval search is not: computing the interval bounds in `double`
|
|
543
|
+
rounds them back to f for an exactly-representable value (collapsing the
|
|
544
|
+
interval) and amplifies rounding at the ulp scale for others. */
|
|
545
|
+
sp_Rational sp_float_rationalize0(sp_float f) {
|
|
546
|
+
if (isnan(f) || isinf(f)) sp_raise_cls("FloatDomainError", isnan(f) ? "NaN" : "Infinity");
|
|
547
|
+
if (f == 0.0) { sp_Rational z; z.num = 0; z.den = 1; return z; }
|
|
548
|
+
int neg = f < 0.0;
|
|
549
|
+
double x = neg ? -(double)f : (double)f;
|
|
550
|
+
double v = x;
|
|
551
|
+
sp_rat_wide h0 = 1, h1 = 0, k0 = 0, k1 = 1; /* convergent num/den recurrences */
|
|
552
|
+
sp_rat_wide num = 0, den = 1;
|
|
553
|
+
int found = 0;
|
|
554
|
+
for (int i = 0; i < 64 && !found; i++) {
|
|
555
|
+
/* floor(v) out of sp_rat_wide range would make the cast below UB; any such
|
|
556
|
+
convergent exceeds INTPTR_MAX anyway, so bail to the exact-ratio fallback. */
|
|
557
|
+
if (v > (double)INTPTR_MAX) break;
|
|
558
|
+
sp_rat_wide a = (sp_rat_wide)floor(v);
|
|
559
|
+
/* guard the convergent against sp_int overflow before forming it (all in
|
|
560
|
+
integer arithmetic: a*h0 + h1 <= INTPTR_MAX). */
|
|
561
|
+
if (a > 0 && (h0 > ((sp_rat_wide)INTPTR_MAX - h1) / a ||
|
|
562
|
+
k0 > ((sp_rat_wide)INTPTR_MAX - k1) / a))
|
|
563
|
+
break;
|
|
564
|
+
sp_rat_wide h = a * h0 + h1;
|
|
565
|
+
sp_rat_wide k = a * k0 + k1;
|
|
566
|
+
num = h; den = k;
|
|
567
|
+
if (k != 0 && (double)h / (double)k == x) { found = 1; break; }
|
|
568
|
+
h1 = h0; h0 = h; k1 = k0; k0 = k;
|
|
569
|
+
double frac = v - a;
|
|
570
|
+
if (frac == 0.0) break;
|
|
571
|
+
v = 1.0 / frac;
|
|
572
|
+
}
|
|
573
|
+
if (!found) return sp_float_to_rational(f); /* fallback: exact bit ratio */
|
|
574
|
+
return sp_rational_new_wide(neg ? -num : num, den);
|
|
575
|
+
}
|
|
576
|
+
/* Rational#round with no digits: nearest integer, ties away from zero
|
|
577
|
+
(CRuby's Rational#round default; den > 0 by construction). */
|
|
578
|
+
sp_int sp_rational_round_i(sp_Rational a) {
|
|
579
|
+
sp_rat_wide q = a.num / a.den, r = a.num % a.den;
|
|
580
|
+
if (r != 0) {
|
|
581
|
+
sp_rat_wide r2 = (r < 0 ? -r : r) * 2;
|
|
582
|
+
if (r2 >= a.den) q += a.num < 0 ? -1 : 1;
|
|
583
|
+
}
|
|
584
|
+
return sp_rat_fit(q);
|
|
585
|
+
}
|
|
586
|
+
/* Rational#round(half: :even): ties go to the even neighbor (#3047). */
|
|
587
|
+
sp_int sp_rational_round_i_even(sp_Rational a) {
|
|
588
|
+
sp_rat_wide q = a.num / a.den, r = a.num % a.den;
|
|
589
|
+
if (r != 0) {
|
|
590
|
+
sp_rat_wide r2 = (r < 0 ? -r : r) * 2;
|
|
591
|
+
if (r2 > a.den) q += a.num < 0 ? -1 : 1; /* past the half: round away */
|
|
592
|
+
else if (r2 == a.den && (q % 2 != 0)) q += a.num < 0 ? -1 : 1; /* tie: to even */
|
|
593
|
+
}
|
|
594
|
+
return sp_rat_fit(q);
|
|
595
|
+
}
|
|
596
|
+
/* Rational#round(half: :down): ties go toward zero (#3047). */
|
|
597
|
+
sp_int sp_rational_round_i_down(sp_Rational a) {
|
|
598
|
+
sp_rat_wide q = a.num / a.den, r = a.num % a.den;
|
|
599
|
+
if (r != 0) {
|
|
600
|
+
sp_rat_wide r2 = (r < 0 ? -r : r) * 2;
|
|
601
|
+
if (r2 > a.den) q += a.num < 0 ? -1 : 1; /* past the half: round away */
|
|
602
|
+
/* an exact tie keeps the toward-zero truncated quotient */
|
|
603
|
+
}
|
|
604
|
+
return sp_rat_fit(q);
|
|
605
|
+
}
|
|
606
|
+
/* Rational#div: floor division to an Integer (CRuby Numeric#div). */
|
|
607
|
+
sp_int sp_rational_idiv(sp_Rational a, sp_Rational b) {
|
|
608
|
+
if (b.num == 0) sp_raise_cls("ZeroDivisionError", "divided by 0");
|
|
609
|
+
sp_rat_wide n = (sp_rat_wide)a.num * b.den, d = (sp_rat_wide)a.den * b.num;
|
|
610
|
+
if (d < 0) { n = -n; d = -d; }
|
|
611
|
+
sp_rat_wide q = n / d;
|
|
612
|
+
if (n % d != 0 && n < 0) q--;
|
|
613
|
+
return sp_rat_fit(q);
|
|
614
|
+
}
|
|
615
|
+
/* 10^e as a wide integer, raising RangeError past the sp_int range. */
|
|
616
|
+
static sp_rat_wide sp_rat_pow10(sp_int e) {
|
|
617
|
+
sp_rat_wide r = 1;
|
|
618
|
+
for (sp_int i = 0; i < e; i++) {
|
|
619
|
+
if (r > (sp_rat_wide)INTPTR_MAX / 10)
|
|
620
|
+
sp_raise_cls("RangeError", "Rational out of sp_int range");
|
|
621
|
+
r *= 10;
|
|
622
|
+
}
|
|
623
|
+
return r;
|
|
624
|
+
}
|
|
625
|
+
/* Rational#round/#truncate with a precision: scale by 10^nd, round or chop to
|
|
626
|
+
an integer, scale back. nd <= 0 yields an integer-valued Rational (den 1);
|
|
627
|
+
codegen realizes the Integer class from the literal precision. */
|
|
628
|
+
sp_int sp_rational_floor_i(sp_Rational a) {
|
|
629
|
+
return a.num >= 0 ? a.num / a.den : -((-a.num + a.den - 1) / a.den);
|
|
630
|
+
}
|
|
631
|
+
sp_int sp_rational_ceil_i(sp_Rational a) {
|
|
632
|
+
return a.num >= 0 ? (a.num + a.den - 1) / a.den : -((-a.num) / a.den);
|
|
633
|
+
}
|
|
634
|
+
/* Rational#round's tie-break rule as the 0 even / 1 up / 2 down code the
|
|
635
|
+
other numeric paths take, so a mode read at run time reaches the same
|
|
636
|
+
three answers the named forms give. */
|
|
637
|
+
sp_int sp_rational_round_i_mode(sp_Rational a, int md) {
|
|
638
|
+
if (md == 0) return sp_rational_round_i_even(a);
|
|
639
|
+
if (md == 2) return sp_rational_round_i_down(a);
|
|
640
|
+
return sp_rational_round_i(a);
|
|
641
|
+
}
|
|
642
|
+
sp_Rational sp_rational_round_prec_mode(sp_Rational a, sp_int nd, int md) {
|
|
643
|
+
sp_rat_wide p = sp_rat_pow10(nd < 0 ? -nd : nd);
|
|
644
|
+
sp_Rational s = nd >= 0 ? sp_rational_new_wide((sp_rat_wide)a.num * p, a.den)
|
|
645
|
+
: sp_rational_new_wide(a.num, (sp_rat_wide)a.den * p);
|
|
646
|
+
sp_int q = sp_rational_round_i_mode(s, md);
|
|
647
|
+
return nd >= 0 ? sp_rational_new_wide(q, p) : sp_rational_new_wide((sp_rat_wide)q * p, 1);
|
|
648
|
+
}
|
|
649
|
+
sp_Rational sp_rational_round_prec(sp_Rational a, sp_int nd) {
|
|
650
|
+
return sp_rational_round_prec_mode(a, nd, 1);
|
|
651
|
+
}
|
|
652
|
+
sp_Rational sp_rational_mod(sp_Rational a, sp_Rational b) {
|
|
653
|
+
sp_int q = sp_rational_idiv(a, b);
|
|
654
|
+
return sp_rational_sub(a, sp_rational_mul(b, sp_rational_new(q, 1)));
|
|
655
|
+
}
|
|
656
|
+
sp_Rational sp_rational_rem(sp_Rational a, sp_Rational b) {
|
|
657
|
+
sp_Rational d = sp_rational_div(a, b);
|
|
658
|
+
sp_int q = d.num / d.den; /* toward zero */
|
|
659
|
+
return sp_rational_sub(a, sp_rational_mul(b, sp_rational_new(q, 1)));
|
|
660
|
+
}
|
|
661
|
+
sp_Rational sp_rational_floor_prec(sp_Rational a, sp_int nd) {
|
|
662
|
+
sp_rat_wide p = sp_rat_pow10(nd < 0 ? -nd : nd);
|
|
663
|
+
sp_Rational s = nd >= 0 ? sp_rational_new_wide((sp_rat_wide)a.num * p, a.den)
|
|
664
|
+
: sp_rational_new_wide(a.num, (sp_rat_wide)a.den * p);
|
|
665
|
+
sp_int q = sp_rational_floor_i(s);
|
|
666
|
+
return nd >= 0 ? sp_rational_new_wide(q, p) : sp_rational_new_wide((sp_rat_wide)q * p, 1);
|
|
667
|
+
}
|
|
668
|
+
sp_Rational sp_rational_ceil_prec(sp_Rational a, sp_int nd) {
|
|
669
|
+
sp_rat_wide p = sp_rat_pow10(nd < 0 ? -nd : nd);
|
|
670
|
+
sp_Rational s = nd >= 0 ? sp_rational_new_wide((sp_rat_wide)a.num * p, a.den)
|
|
671
|
+
: sp_rational_new_wide(a.num, (sp_rat_wide)a.den * p);
|
|
672
|
+
sp_int q = sp_rational_ceil_i(s);
|
|
673
|
+
return nd >= 0 ? sp_rational_new_wide(q, p) : sp_rational_new_wide((sp_rat_wide)q * p, 1);
|
|
674
|
+
}
|
|
675
|
+
sp_Rational sp_rational_truncate_prec(sp_Rational a, sp_int nd) {
|
|
676
|
+
sp_rat_wide p = sp_rat_pow10(nd < 0 ? -nd : nd);
|
|
677
|
+
sp_Rational s = nd >= 0 ? sp_rational_new_wide((sp_rat_wide)a.num * p, a.den)
|
|
678
|
+
: sp_rational_new_wide(a.num, (sp_rat_wide)a.den * p);
|
|
679
|
+
sp_int q = s.num / s.den; /* toward zero */
|
|
680
|
+
return nd >= 0 ? sp_rational_new_wide(q, p) : sp_rational_new_wide((sp_rat_wide)q * p, 1);
|
|
681
|
+
}
|
|
682
|
+
static sp_rat_wide sp_rat_ipow(sp_rat_wide base, sp_int e) {
|
|
683
|
+
sp_rat_wide r = 1;
|
|
684
|
+
for (sp_int i = 0; i < e; i++) {
|
|
685
|
+
r *= base;
|
|
686
|
+
if (r > (sp_rat_wide)INTPTR_MAX || r < (sp_rat_wide)(-INTPTR_MAX))
|
|
687
|
+
sp_raise_cls("RangeError", "Rational out of sp_int range");
|
|
688
|
+
}
|
|
689
|
+
return r;
|
|
690
|
+
}
|
|
691
|
+
sp_Rational sp_rational_pow(sp_Rational a, sp_int e) {
|
|
692
|
+
if (e >= 0) return sp_rational_new_wide(sp_rat_ipow(a.num, e), sp_rat_ipow(a.den, e));
|
|
693
|
+
if (a.num == 0) sp_raise_cls("ZeroDivisionError", "divided by 0");
|
|
694
|
+
return sp_rational_new_wide(sp_rat_ipow(a.den, -e), sp_rat_ipow(a.num, -e));
|
|
695
|
+
}
|