quadmath 0.1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +11 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +160 -0
- data/Rakefile +14 -0
- data/ext/quadmath/complex128.c +494 -0
- data/ext/quadmath/extconf.rb +15 -0
- data/ext/quadmath/float128.c +638 -0
- data/ext/quadmath/internal/rb_quadmath.h +77 -0
- data/ext/quadmath/main.c +31 -0
- data/ext/quadmath/missing/cerfcq.c +158 -0
- data/ext/quadmath/missing/cerfq.c +35 -0
- data/ext/quadmath/missing/cl2norm2q.c +43 -0
- data/ext/quadmath/missing/clgammaq.c +61 -0
- data/ext/quadmath/missing/ctgammaq.c +56 -0
- data/ext/quadmath/missing/ool_quad2str.c +738 -0
- data/ext/quadmath/missing/opts_exception_p.c +20 -0
- data/ext/quadmath/numerable.c +2657 -0
- data/ext/quadmath/quadmath.c +2768 -0
- data/ext/quadmath/rb_quadmath.h +75 -0
- data/lib/quadmath/quadmath.so +0 -0
- data/lib/quadmath/version.rb +5 -0
- data/lib/quadmath.rb +8 -0
- data/pkg/quadmath-0.1.0.gem +0 -0
- data/sig/ruby/quadmath.rbs +6 -0
- metadata +70 -0
|
@@ -0,0 +1,2657 @@
|
|
|
1
|
+
/*******************************************************************************
|
|
2
|
+
numerable.c -- Numerable for quadmath arithmetic
|
|
3
|
+
|
|
4
|
+
Author: Hironobu Inatsuka
|
|
5
|
+
*******************************************************************************/
|
|
6
|
+
#include <ruby.h>
|
|
7
|
+
#include <quadmath.h>
|
|
8
|
+
#include "rb_quadmath.h"
|
|
9
|
+
#include "internal/rb_quadmath.h"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
#define OPE_ADD 1
|
|
13
|
+
#define OPE_SUB 2
|
|
14
|
+
#define OPE_MUL 3
|
|
15
|
+
#define OPE_DIV 4
|
|
16
|
+
#define OPE_MOD 5
|
|
17
|
+
#define OPE_POW 6
|
|
18
|
+
#define OPE_CMP 7
|
|
19
|
+
#define OPE_COERCE 8
|
|
20
|
+
|
|
21
|
+
#define FMT_EMPTY 0
|
|
22
|
+
#define FMT_DRCTV 1
|
|
23
|
+
#define FMT_WIDTH 2
|
|
24
|
+
#define FMT_WIDTH_SCALAR 3
|
|
25
|
+
#define FMT_POINT 4
|
|
26
|
+
#define FMT_PREC 5
|
|
27
|
+
#define FMT_PREC_SCALAR 6
|
|
28
|
+
#define FMT_SET_FT 7
|
|
29
|
+
|
|
30
|
+
#define FLAG_SHARP 0x1
|
|
31
|
+
#define FLAG_ZERO 0x2
|
|
32
|
+
#define FLAG_SPACE 0x4
|
|
33
|
+
#define FLAG_PLUS 0x8
|
|
34
|
+
#define FLAG_MINUS 0x10
|
|
35
|
+
|
|
36
|
+
#define FT_FLT 0
|
|
37
|
+
#define FT_DBL 1
|
|
38
|
+
#define FT_LDBL 2
|
|
39
|
+
#define FT_QUAD 3
|
|
40
|
+
|
|
41
|
+
#define BUF_SIZ 128
|
|
42
|
+
|
|
43
|
+
__complex128
|
|
44
|
+
cmodq(__complex128 z, __complex128 w)
|
|
45
|
+
{
|
|
46
|
+
return 0+0i; // 未定義
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static inline VALUE
|
|
50
|
+
numeric_to_f128_inline(VALUE self, int exception)
|
|
51
|
+
{
|
|
52
|
+
|
|
53
|
+
if (!rb_respond_to(self, rb_intern("to_f128")))
|
|
54
|
+
{
|
|
55
|
+
if (!exception)
|
|
56
|
+
return Qnil;
|
|
57
|
+
else
|
|
58
|
+
rb_raise(rb_eNoMethodError,
|
|
59
|
+
"can't convert %"PRIsVALUE" into %s",
|
|
60
|
+
rb_String(self), rb_class2name(rb_cFloat128));
|
|
61
|
+
}
|
|
62
|
+
else
|
|
63
|
+
return rb_funcall(self, rb_intern("to_f128"), 0);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/*
|
|
67
|
+
* call-seq:
|
|
68
|
+
* to_f128 -> Float128
|
|
69
|
+
*
|
|
70
|
+
* A hook for subclasses that require the system to convert to Float128 type.
|
|
71
|
+
* Internally it calls a method. In reality it is undefined.
|
|
72
|
+
*/
|
|
73
|
+
static VALUE
|
|
74
|
+
numeric_to_f128(VALUE self)
|
|
75
|
+
{
|
|
76
|
+
return numeric_to_f128_inline(self, true);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
static inline VALUE
|
|
80
|
+
numeric_to_c128_inline(VALUE self, int exception)
|
|
81
|
+
{
|
|
82
|
+
if (!rb_respond_to(self, rb_intern("to_c128")))
|
|
83
|
+
{
|
|
84
|
+
if (!exception)
|
|
85
|
+
return Qnil;
|
|
86
|
+
else
|
|
87
|
+
rb_raise(rb_eNoMethodError,
|
|
88
|
+
"can't convert %"PRIsVALUE" into %s",
|
|
89
|
+
rb_String(self), rb_class2name(rb_cComplex128));
|
|
90
|
+
}
|
|
91
|
+
else
|
|
92
|
+
return rb_funcall(self, rb_intern("to_c128"), 0);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/*
|
|
96
|
+
* call-seq:
|
|
97
|
+
* to_c128 -> Complex128
|
|
98
|
+
*
|
|
99
|
+
* A hook for subclasses that require the system to convert to Float128 type.
|
|
100
|
+
* Internally it calls a method. In reality it is undefined.
|
|
101
|
+
*/
|
|
102
|
+
static VALUE
|
|
103
|
+
numeric_to_c128(VALUE self)
|
|
104
|
+
{
|
|
105
|
+
return numeric_to_c128_inline(self, true);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
static VALUE
|
|
109
|
+
string_to_f128_inline(VALUE self, int exception)
|
|
110
|
+
{
|
|
111
|
+
char *sp = NULL;
|
|
112
|
+
__float128 x = strtoflt128(StringValuePtr(self), &sp);
|
|
113
|
+
|
|
114
|
+
if (strlen(sp) != 0)
|
|
115
|
+
{
|
|
116
|
+
if (exception == true)
|
|
117
|
+
rb_raise(rb_eArgError,
|
|
118
|
+
"invalid value for Float128(): %"PRIsVALUE"", self);
|
|
119
|
+
else
|
|
120
|
+
return Qnil;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return rb_float128_cf128(x);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/*
|
|
127
|
+
* call-seq:
|
|
128
|
+
* to_f128 -> Float128
|
|
129
|
+
*
|
|
130
|
+
* Creates a Float128 type from a String. Implemented as a library function.
|
|
131
|
+
*
|
|
132
|
+
* '1.3'.to_f128 # => 1.3
|
|
133
|
+
* 1.3.to_f128 # => 1.3000000000000000444089209850062
|
|
134
|
+
* Float128('true') #=> ArgumentError
|
|
135
|
+
*/
|
|
136
|
+
static VALUE
|
|
137
|
+
string_to_f128(VALUE self)
|
|
138
|
+
{
|
|
139
|
+
VALUE val = string_to_f128_inline(self, false);
|
|
140
|
+
|
|
141
|
+
if (NIL_P(val))
|
|
142
|
+
val = rb_float128_cf128(0);
|
|
143
|
+
|
|
144
|
+
return val;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
static VALUE
|
|
148
|
+
string_to_c128_inline(VALUE self, int exception)
|
|
149
|
+
{
|
|
150
|
+
char *sp = NULL;
|
|
151
|
+
__float128 x = strtoflt128(StringValuePtr(self), &sp);
|
|
152
|
+
__complex128 z = 0+0i;
|
|
153
|
+
|
|
154
|
+
if (strlen(sp) == 0)
|
|
155
|
+
__real__ z = x;
|
|
156
|
+
else
|
|
157
|
+
{
|
|
158
|
+
const char c = sp[0];
|
|
159
|
+
switch (c) {
|
|
160
|
+
case 'i':
|
|
161
|
+
if (strlen(sp) == 1)
|
|
162
|
+
{
|
|
163
|
+
__imag__ z = x;
|
|
164
|
+
goto retval;
|
|
165
|
+
}
|
|
166
|
+
break;
|
|
167
|
+
case '+': case '-':
|
|
168
|
+
__real__ z = x;
|
|
169
|
+
__imag__ z = strtoflt128(sp, &sp);
|
|
170
|
+
if (strlen(sp) == 1 && sp[0] == 'i')
|
|
171
|
+
goto retval;
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
if (exception == true)
|
|
175
|
+
rb_raise(rb_eArgError,
|
|
176
|
+
"invalid value for Complex128(): %"PRIsVALUE"", self);
|
|
177
|
+
else
|
|
178
|
+
return Qnil;
|
|
179
|
+
}
|
|
180
|
+
retval:
|
|
181
|
+
return rb_complex128_cc128(z);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/*
|
|
185
|
+
* call-seq:
|
|
186
|
+
* to_c128 -> Complex128
|
|
187
|
+
*
|
|
188
|
+
* Creates a Complex128 type from a String. Implemented as a library function.
|
|
189
|
+
*
|
|
190
|
+
* Complex128('-12i') #=> (0.0-12.0i)
|
|
191
|
+
* Complex128('-1+12i') #=> (-1.0+12.0i)
|
|
192
|
+
* Complex128('1.0e2+1e1i') #=> (100.0+10.0i)
|
|
193
|
+
*/
|
|
194
|
+
static VALUE
|
|
195
|
+
string_to_c128(VALUE self)
|
|
196
|
+
{
|
|
197
|
+
VALUE val = string_to_c128_inline(self, false);
|
|
198
|
+
|
|
199
|
+
if (NIL_P(val))
|
|
200
|
+
val = rb_complex128_cc128(0+0i);
|
|
201
|
+
|
|
202
|
+
return val;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
static inline __float128
|
|
206
|
+
integer_to_cf128(VALUE self)
|
|
207
|
+
{
|
|
208
|
+
__float128 x = 0.0Q;
|
|
209
|
+
switch (TYPE(self)) {
|
|
210
|
+
case T_FIXNUM:
|
|
211
|
+
x = (__float128)FIX2LONG(self);
|
|
212
|
+
break;
|
|
213
|
+
case T_BIGNUM:
|
|
214
|
+
VALUE inum = rb_big2str(self, 10);
|
|
215
|
+
x = strtoflt128(StringValuePtr(inum), NULL);
|
|
216
|
+
default:
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
return x;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/*
|
|
223
|
+
* call-seq:
|
|
224
|
+
* to_f128 -> Float128
|
|
225
|
+
*
|
|
226
|
+
* Converts from Integer to Float128 type.
|
|
227
|
+
* Internally, the conversion is performed in a way that minimizes loss of precision.
|
|
228
|
+
*
|
|
229
|
+
* 1.to_f128 # => 1.0
|
|
230
|
+
* (-1024**1024).to_f128 # => -3.52497141210838265713481483980028e+3082
|
|
231
|
+
*/
|
|
232
|
+
static VALUE
|
|
233
|
+
integer_to_f128(VALUE self)
|
|
234
|
+
{
|
|
235
|
+
__float128 x = integer_to_cf128(self);
|
|
236
|
+
|
|
237
|
+
return rb_float128_cf128(x);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/*
|
|
241
|
+
* call-seq:
|
|
242
|
+
* to_c128 -> Complex128
|
|
243
|
+
*
|
|
244
|
+
* Convert from Integer to Complex128 type.
|
|
245
|
+
* It has the same implementation as to_f128, but first converts to Float128 type and then performs type casting at the C level.
|
|
246
|
+
*
|
|
247
|
+
* -1.to_c128 # => (-1.0+0.0i)
|
|
248
|
+
|
|
249
|
+
*/
|
|
250
|
+
static VALUE
|
|
251
|
+
integer_to_c128(VALUE self)
|
|
252
|
+
{
|
|
253
|
+
__complex128 z = (__complex128)integer_to_cf128(self);
|
|
254
|
+
return rb_complex128_cc128(z);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
static inline __float128
|
|
260
|
+
rational_to_cf128(VALUE self)
|
|
261
|
+
{
|
|
262
|
+
VALUE numer = rb_rational_num(self),
|
|
263
|
+
denom = rb_rational_den(self);
|
|
264
|
+
|
|
265
|
+
return integer_to_cf128(numer) / integer_to_cf128(denom);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/*
|
|
269
|
+
* call-seq:
|
|
270
|
+
* to_f128 -> Float128
|
|
271
|
+
*
|
|
272
|
+
* Convert from Rational to Float128 type.
|
|
273
|
+
* Accurate type conversion can be expected because the conversion involves extracting the numerator and denominator separately and then dividing them.
|
|
274
|
+
* When Rational is generated from double precision, some valuesmay be missing information.
|
|
275
|
+
*
|
|
276
|
+
* (-1/3r).to_f128 # => -0.333333333333333333333333333333333
|
|
277
|
+
* Rational(2.1).to_f128 # => 2.1000000000000000888178419700125
|
|
278
|
+
*/
|
|
279
|
+
static VALUE
|
|
280
|
+
rational_to_f128(VALUE self)
|
|
281
|
+
{
|
|
282
|
+
__float128 x = rational_to_cf128(self);
|
|
283
|
+
|
|
284
|
+
return rb_float128_cf128(x);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/*
|
|
288
|
+
* call-seq:
|
|
289
|
+
* to_c128 -> Complex128
|
|
290
|
+
*
|
|
291
|
+
* Convert from Rational to Complex128 type.
|
|
292
|
+
* It has the same implementation as to_f128, but it is first converted to Float128 and then typecast at the C level.
|
|
293
|
+
*
|
|
294
|
+
* Rational(-1, 2).to_c128 # => (-0.5+0.0i)
|
|
295
|
+
*/
|
|
296
|
+
static VALUE
|
|
297
|
+
rational_to_c128(VALUE self)
|
|
298
|
+
{
|
|
299
|
+
__complex128 z = (__complex128)rational_to_cf128(self);
|
|
300
|
+
return rb_complex128_cc128(z);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
/*
|
|
305
|
+
* call-seq:
|
|
306
|
+
* to_f128 -> Float128
|
|
307
|
+
*
|
|
308
|
+
* Converts Float to Float128 type. Type casting is performed at the C level.
|
|
309
|
+
* Note that this is a conversion from double to quad precision, so information may be lost.
|
|
310
|
+
*
|
|
311
|
+
* Float::INFINITY.to_f128 == Float::INFINITY # => true
|
|
312
|
+
* -Float('1').to_f128 == Float128('-1.0') # => true
|
|
313
|
+
* -Float('1.1').to_f128 == Float128('-1.1') # => false
|
|
314
|
+
*
|
|
315
|
+
*/
|
|
316
|
+
static VALUE
|
|
317
|
+
float_to_f128(VALUE self)
|
|
318
|
+
{
|
|
319
|
+
double x = NUM2DBL(self);
|
|
320
|
+
|
|
321
|
+
return rb_float128_cf128((__float128)x);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/*
|
|
325
|
+
* call-seq:
|
|
326
|
+
* to_c128 -> Complex128
|
|
327
|
+
*
|
|
328
|
+
* Converts Float to Complex128 type. Type casting is performed at the C level.
|
|
329
|
+
* Note that this is a conversion from double to quad precision, so information may be lost.
|
|
330
|
+
*
|
|
331
|
+
* Float::INFINITY.to_c128 # => (Infinity+0.0i)
|
|
332
|
+
* c128 = 1.5.to_c128 # => (1.5+0.0i)
|
|
333
|
+
* c128.class # => Complex128
|
|
334
|
+
*/
|
|
335
|
+
static VALUE
|
|
336
|
+
float_to_c128(VALUE self)
|
|
337
|
+
{
|
|
338
|
+
double x = NUM2DBL(self);
|
|
339
|
+
return rb_complex128_cc128((__complex128)x);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
static inline __float128
|
|
345
|
+
elem_to_cf128(VALUE self)
|
|
346
|
+
{
|
|
347
|
+
__float128 x;
|
|
348
|
+
switch (TYPE(self)) {
|
|
349
|
+
case T_FIXNUM:
|
|
350
|
+
case T_BIGNUM:
|
|
351
|
+
x = integer_to_cf128(self);
|
|
352
|
+
break;
|
|
353
|
+
case T_RATIONAL:
|
|
354
|
+
x = rational_to_cf128(self);
|
|
355
|
+
break;
|
|
356
|
+
case T_FLOAT:
|
|
357
|
+
x = (__float128)NUM2DBL(self);
|
|
358
|
+
break;
|
|
359
|
+
default:
|
|
360
|
+
if (CLASS_OF(self) != rb_cFloat128)
|
|
361
|
+
self = rb_funcall(self, rb_intern("to_f128"), 0);
|
|
362
|
+
|
|
363
|
+
x = rb_float128_value(self);
|
|
364
|
+
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
return x;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
static inline VALUE
|
|
372
|
+
nucomp_to_f128_inline(VALUE self, int exception)
|
|
373
|
+
{
|
|
374
|
+
VALUE real = rb_complex_real(self),
|
|
375
|
+
imag = rb_complex_imag(self);
|
|
376
|
+
|
|
377
|
+
if (elem_to_cf128(imag) != 0)
|
|
378
|
+
{
|
|
379
|
+
if (!exception)
|
|
380
|
+
return Qnil;
|
|
381
|
+
else
|
|
382
|
+
rb_raise(rb_eRangeError,
|
|
383
|
+
"can't convert %"PRIsVALUE" into %s",
|
|
384
|
+
rb_String(self), rb_class2name(rb_cFloat128));
|
|
385
|
+
}
|
|
386
|
+
return rb_float128_cf128(elem_to_cf128(real));
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
static VALUE
|
|
390
|
+
nucomp_to_f128(VALUE self)
|
|
391
|
+
{
|
|
392
|
+
return nucomp_to_f128_inline(self, true);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
static VALUE
|
|
396
|
+
nucomp_to_c128(VALUE self)
|
|
397
|
+
{
|
|
398
|
+
VALUE real = rb_complex_real(self),
|
|
399
|
+
imag = rb_complex_imag(self);
|
|
400
|
+
__complex128 z;
|
|
401
|
+
__real__ z = elem_to_cf128(real);
|
|
402
|
+
__imag__ z = elem_to_cf128(imag);
|
|
403
|
+
|
|
404
|
+
return rb_complex128_cc128(z);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
static inline VALUE
|
|
408
|
+
complex128_to_f128_inline(VALUE self, int exception)
|
|
409
|
+
{
|
|
410
|
+
__complex128 z = rb_complex128_value(self);
|
|
411
|
+
|
|
412
|
+
if (cimagq(z) != 0)
|
|
413
|
+
{
|
|
414
|
+
if (!exception)
|
|
415
|
+
return Qnil;
|
|
416
|
+
else
|
|
417
|
+
rb_raise(rb_eRangeError,
|
|
418
|
+
"can't convert %"PRIsVALUE" into %s",
|
|
419
|
+
rb_String(self), rb_class2name(rb_cFloat128));
|
|
420
|
+
}
|
|
421
|
+
return rb_float128_cf128(crealq(z));
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
static inline VALUE
|
|
425
|
+
float128_to_c128_inline(VALUE self)
|
|
426
|
+
{
|
|
427
|
+
__float128 x = rb_float128_value(self);
|
|
428
|
+
|
|
429
|
+
return rb_complex128_cc128((__complex128)x);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/*
|
|
433
|
+
* call-seq:
|
|
434
|
+
* Float128(val) -> Float128
|
|
435
|
+
* Float128(val, exception: false) -> Float128 | nil
|
|
436
|
+
*
|
|
437
|
+
* Generates a Float128 from +val+. +val+ can be generated from +self+ or other numeric classes, String, etc.
|
|
438
|
+
* If the conversion is not possible, a RangeError is raised.
|
|
439
|
+
* Literals are converted to quadruple precision whenever possible. However, caution is required when converting from double precision, as there is a low chance that precision will be preserved.
|
|
440
|
+
* By setting the keyword argument exception to false, nil will be returned in the event of an exception.
|
|
441
|
+
*
|
|
442
|
+
* Float128(1) # => 1.0
|
|
443
|
+
* Float128(2.0) # => 2.0
|
|
444
|
+
* Float128(2.1) # => 2.1000000000000000888178419700125
|
|
445
|
+
* Float128('2.1') # => 2.1
|
|
446
|
+
* Float128(1.0/3.0) # => 0.333333333333333314829616256247391
|
|
447
|
+
* Float128(1/3r) # => 0.333333333333333333333333333333333
|
|
448
|
+
* Float128(1+0i) # => 1.0
|
|
449
|
+
* Float128(1i) # => RangeError
|
|
450
|
+
* Float128(1i, exception: false) # => nil
|
|
451
|
+
* Float128('1+1', exception: false) # => nil
|
|
452
|
+
*/
|
|
453
|
+
static VALUE
|
|
454
|
+
f_Float128(int argc, VALUE *argv, VALUE self)
|
|
455
|
+
{
|
|
456
|
+
VALUE val, opts = Qnil;
|
|
457
|
+
argc = rb_scan_args(argc, argv, "11", &val, &opts);
|
|
458
|
+
int exception = opts_exception_p(opts);
|
|
459
|
+
|
|
460
|
+
switch (TYPE(val)) {
|
|
461
|
+
case T_FIXNUM:
|
|
462
|
+
case T_BIGNUM:
|
|
463
|
+
val = integer_to_f128(val);
|
|
464
|
+
break;
|
|
465
|
+
case T_RATIONAL:
|
|
466
|
+
val = rational_to_f128(val);
|
|
467
|
+
break;
|
|
468
|
+
case T_FLOAT:
|
|
469
|
+
val = float_to_f128(val);
|
|
470
|
+
break;
|
|
471
|
+
case T_COMPLEX:
|
|
472
|
+
val = nucomp_to_f128_inline(val, exception);
|
|
473
|
+
break;
|
|
474
|
+
case T_STRING:
|
|
475
|
+
val = string_to_f128_inline(val, exception);
|
|
476
|
+
break;
|
|
477
|
+
default:
|
|
478
|
+
if (CLASS_OF(val) == rb_cFloat128);
|
|
479
|
+
else if (CLASS_OF(val) == rb_cComplex128)
|
|
480
|
+
val = complex128_to_f128_inline(val, exception);
|
|
481
|
+
else
|
|
482
|
+
val = numeric_to_f128_inline(val, exception);
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
485
|
+
return val;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/*
|
|
489
|
+
* call-seq:
|
|
490
|
+
* Complex128(val) -> Complex128
|
|
491
|
+
* Complex128(val, exception: false) -> Complex128 | nil
|
|
492
|
+
*
|
|
493
|
+
* Generates a Complex128 from +val+. +val+ can be generated from +self+ or other numeric classes, String, etc.
|
|
494
|
+
*
|
|
495
|
+
* Complex128(5) # => (5.0+0.0i)
|
|
496
|
+
* Complex128(5.0) # => (5.0+0.0i)
|
|
497
|
+
* Complex128(2/3r) # => (0.666666666666666666666666666666667+0.0i)
|
|
498
|
+
* Complex128(1+2i) # => (1.0+2.0i)
|
|
499
|
+
* Complex128(Float128('1.3')) # => (1.3+0.0i)
|
|
500
|
+
* Complex128(1.3) # => (1.3000000000000000444089209850062+0.0i)
|
|
501
|
+
* Complex128('1.3') # => (1.3+0.0i)
|
|
502
|
+
* Complex128('5i') #=> (0.0+5.0i)
|
|
503
|
+
* Complex128('2-12', exception: false) #=> nil
|
|
504
|
+
*/
|
|
505
|
+
static VALUE
|
|
506
|
+
f_Complex128(int argc, VALUE *argv, VALUE self)
|
|
507
|
+
{
|
|
508
|
+
VALUE val, opts = Qnil;
|
|
509
|
+
argc = rb_scan_args(argc, argv, "11", &val, &opts);
|
|
510
|
+
int exception = opts_exception_p(opts);
|
|
511
|
+
|
|
512
|
+
switch (TYPE(val)) {
|
|
513
|
+
case T_FIXNUM:
|
|
514
|
+
case T_BIGNUM:
|
|
515
|
+
val = integer_to_c128(val);
|
|
516
|
+
break;
|
|
517
|
+
case T_RATIONAL:
|
|
518
|
+
val = rational_to_c128(val);
|
|
519
|
+
break;
|
|
520
|
+
case T_FLOAT:
|
|
521
|
+
val = float_to_c128(val);
|
|
522
|
+
break;
|
|
523
|
+
case T_COMPLEX:
|
|
524
|
+
val = nucomp_to_c128(val);
|
|
525
|
+
break;
|
|
526
|
+
case T_STRING:
|
|
527
|
+
val = string_to_c128_inline(val, exception);
|
|
528
|
+
break;
|
|
529
|
+
default:
|
|
530
|
+
if (CLASS_OF(val) == rb_cComplex128);
|
|
531
|
+
else if (CLASS_OF(val) == rb_cFloat128)
|
|
532
|
+
val = float128_to_c128_inline(val);
|
|
533
|
+
else
|
|
534
|
+
val = numeric_to_c128_inline(val, exception);
|
|
535
|
+
break;
|
|
536
|
+
}
|
|
537
|
+
return val;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
/*
|
|
542
|
+
* call-seq:
|
|
543
|
+
* polar -> [Float128, Float128]
|
|
544
|
+
*
|
|
545
|
+
* Returns the absolute value and argument of +self+ as an array. It behaves the same as Float but has different precision.
|
|
546
|
+
*
|
|
547
|
+
* 1.0.polar # => [1.0, 0]
|
|
548
|
+
* Float128('2.0').polar # => [2.0, 0]
|
|
549
|
+
* -1.0.polar # => [1.0, 3.141592653589793]
|
|
550
|
+
* Float128('-1.0').polar # => [1.0, 3.1415926535897932384626433832795]
|
|
551
|
+
*
|
|
552
|
+
*/
|
|
553
|
+
static VALUE
|
|
554
|
+
float128_polar(VALUE self)
|
|
555
|
+
{
|
|
556
|
+
__float128 f128 = GetF128(self);
|
|
557
|
+
|
|
558
|
+
if (signbitq(f128))
|
|
559
|
+
return rb_assoc_new(
|
|
560
|
+
rb_float128_cf128(fabsq(f128)),
|
|
561
|
+
rb_float128_cf128(M_PIq));
|
|
562
|
+
else
|
|
563
|
+
return rb_assoc_new(
|
|
564
|
+
rb_float128_cf128(fabsq(f128)),
|
|
565
|
+
INT2NUM(0));
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
/*
|
|
570
|
+
* call-seq:
|
|
571
|
+
* abs -> Float128
|
|
572
|
+
* magnitude -> Float128
|
|
573
|
+
*
|
|
574
|
+
* Returns the absolute value of +self+.
|
|
575
|
+
*/
|
|
576
|
+
static VALUE
|
|
577
|
+
float128_abs(VALUE self)
|
|
578
|
+
{
|
|
579
|
+
__float128 f128 = GetF128(self);
|
|
580
|
+
|
|
581
|
+
return rb_float128_cf128(fabsq(f128));
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/*
|
|
585
|
+
* call-seq:
|
|
586
|
+
* abs2 -> Float128
|
|
587
|
+
*
|
|
588
|
+
* Returns the absolute value squared of +self+.
|
|
589
|
+
*/
|
|
590
|
+
static VALUE
|
|
591
|
+
float128_abs2(VALUE self)
|
|
592
|
+
{
|
|
593
|
+
__float128 f128 = GetF128(self);
|
|
594
|
+
|
|
595
|
+
return rb_float128_cf128(f128 * f128);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
/*
|
|
600
|
+
* call-seq:
|
|
601
|
+
* arg -> 0 | QuadMath::PI
|
|
602
|
+
* angle -> 0 | QuadMath::PI
|
|
603
|
+
* phase -> 0 | QuadMath::PI
|
|
604
|
+
*
|
|
605
|
+
* Returns the argument of +self+ (0 if positive, PI if negative).
|
|
606
|
+
* It behaves the same as the Float type, but has different a class.
|
|
607
|
+
*
|
|
608
|
+
* Float128('1').arg # => 0
|
|
609
|
+
* Float128('-1').arg # => 3.1415926535897932384626433832795
|
|
610
|
+
* Float('-1').arg # => 3.141592653589793
|
|
611
|
+
*/
|
|
612
|
+
static VALUE
|
|
613
|
+
float128_arg(VALUE self)
|
|
614
|
+
{
|
|
615
|
+
__float128 f128 = GetF128(self);
|
|
616
|
+
|
|
617
|
+
return signbitq(f128) ?
|
|
618
|
+
rb_float128_cf128(M_PIq) :
|
|
619
|
+
INT2NUM(0);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
static inline __float128
|
|
624
|
+
f128_modulo(__float128 x, __float128 y)
|
|
625
|
+
{
|
|
626
|
+
switch ((signbitq(x) << 1) | signbitq(y)) {
|
|
627
|
+
case 0b00: case 0b11:
|
|
628
|
+
return fmodq(x, y);
|
|
629
|
+
default:
|
|
630
|
+
return x - y * floorq(x / y);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
static inline __float128
|
|
635
|
+
get_real(VALUE num)
|
|
636
|
+
{
|
|
637
|
+
__float128 real;
|
|
638
|
+
VALUE nucomp;
|
|
639
|
+
|
|
640
|
+
switch (convertion_num_types(num)) {
|
|
641
|
+
case NUM_FIXNUM:
|
|
642
|
+
case NUM_BIGNUM:
|
|
643
|
+
real = integer_to_cf128(num);
|
|
644
|
+
break;
|
|
645
|
+
case NUM_RATIONAL:
|
|
646
|
+
real = rational_to_cf128(num);
|
|
647
|
+
break;
|
|
648
|
+
case NUM_FLOAT:
|
|
649
|
+
real = (__float128)NUM2DBL(num);
|
|
650
|
+
break;
|
|
651
|
+
case NUM_COMPLEX:
|
|
652
|
+
nucomp = nucomp_to_f128_inline(num, false);
|
|
653
|
+
if (NIL_P(nucomp)) goto not_a_real;
|
|
654
|
+
real = rb_float128_value(nucomp);
|
|
655
|
+
break;
|
|
656
|
+
case NUM_FLOAT128:
|
|
657
|
+
real = rb_float128_value(num);
|
|
658
|
+
break;
|
|
659
|
+
case NUM_COMPLEX128:
|
|
660
|
+
nucomp = complex128_to_f128_inline(num, false);
|
|
661
|
+
if (NIL_P(nucomp)) goto not_a_real;
|
|
662
|
+
real = rb_float128_value(nucomp);
|
|
663
|
+
break;
|
|
664
|
+
case NUM_OTHERTYPE:
|
|
665
|
+
default:
|
|
666
|
+
if (RTEST(rb_obj_is_kind_of(num, rb_cNumeric)))
|
|
667
|
+
{
|
|
668
|
+
VALUE val = numeric_to_f128_inline(num, false);
|
|
669
|
+
if (NIL_P(val)) goto not_a_real;
|
|
670
|
+
real = rb_float128_value(val);
|
|
671
|
+
}
|
|
672
|
+
else
|
|
673
|
+
goto not_a_real;
|
|
674
|
+
break;
|
|
675
|
+
}
|
|
676
|
+
return real;
|
|
677
|
+
|
|
678
|
+
not_a_real:
|
|
679
|
+
rb_raise(rb_eTypeError, "not a real");
|
|
680
|
+
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
static inline void
|
|
684
|
+
unknown_opecode(void)
|
|
685
|
+
{
|
|
686
|
+
rb_warn("unknown operator code (in %s)", __func__);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
static VALUE
|
|
690
|
+
float128_ope_integer(VALUE self, VALUE other, int ope)
|
|
691
|
+
{
|
|
692
|
+
__float128 x = GetF128(self);
|
|
693
|
+
__float128 y = integer_to_cf128(other);
|
|
694
|
+
|
|
695
|
+
switch (ope) {
|
|
696
|
+
case OPE_ADD:
|
|
697
|
+
return rb_float128_cf128(x + y);
|
|
698
|
+
break;
|
|
699
|
+
case OPE_SUB:
|
|
700
|
+
return rb_float128_cf128(x - y);
|
|
701
|
+
break;
|
|
702
|
+
case OPE_MUL:
|
|
703
|
+
return rb_float128_cf128(x * y);
|
|
704
|
+
break;
|
|
705
|
+
case OPE_DIV:
|
|
706
|
+
return rb_float128_cf128(x / y);
|
|
707
|
+
break;
|
|
708
|
+
case OPE_MOD:
|
|
709
|
+
return rb_float128_cf128(f128_modulo(x, y));
|
|
710
|
+
break;
|
|
711
|
+
case OPE_POW:
|
|
712
|
+
return rb_float128_cf128(powq(x, y));
|
|
713
|
+
break;
|
|
714
|
+
case OPE_CMP:
|
|
715
|
+
if (isnanq(x))
|
|
716
|
+
return Qnil;
|
|
717
|
+
else if (x < y)
|
|
718
|
+
return INT2NUM(-1);
|
|
719
|
+
else if (x > y)
|
|
720
|
+
return INT2NUM(1);
|
|
721
|
+
else /* (x == y) */
|
|
722
|
+
return INT2NUM(0);
|
|
723
|
+
break;
|
|
724
|
+
case OPE_COERCE:
|
|
725
|
+
return rb_assoc_new(
|
|
726
|
+
rb_float128_cf128(y),
|
|
727
|
+
rb_float128_cf128(x));
|
|
728
|
+
break;
|
|
729
|
+
default:
|
|
730
|
+
unknown_opecode();
|
|
731
|
+
return rb_float128_cf128(0.q);
|
|
732
|
+
break;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
static VALUE
|
|
737
|
+
float128_ope_rational(VALUE self, VALUE other, int ope)
|
|
738
|
+
{
|
|
739
|
+
__float128 x = GetF128(self);
|
|
740
|
+
__float128 y = rational_to_cf128(other);
|
|
741
|
+
|
|
742
|
+
switch (ope) {
|
|
743
|
+
case OPE_ADD:
|
|
744
|
+
return rb_float128_cf128(x + y);
|
|
745
|
+
break;
|
|
746
|
+
case OPE_SUB:
|
|
747
|
+
return rb_float128_cf128(x - y);
|
|
748
|
+
break;
|
|
749
|
+
case OPE_MUL:
|
|
750
|
+
return rb_float128_cf128(x * y);
|
|
751
|
+
break;
|
|
752
|
+
case OPE_DIV:
|
|
753
|
+
return rb_float128_cf128(x / y);
|
|
754
|
+
break;
|
|
755
|
+
case OPE_MOD:
|
|
756
|
+
return rb_float128_cf128(f128_modulo(x, y));
|
|
757
|
+
break;
|
|
758
|
+
case OPE_POW:
|
|
759
|
+
return rb_float128_cf128(powq(x, y));
|
|
760
|
+
break;
|
|
761
|
+
case OPE_CMP:
|
|
762
|
+
if (isnanq(x))
|
|
763
|
+
return Qnil;
|
|
764
|
+
else if (x < y)
|
|
765
|
+
return INT2NUM(-1);
|
|
766
|
+
else if (x > y)
|
|
767
|
+
return INT2NUM(1);
|
|
768
|
+
else /* (x == y) */
|
|
769
|
+
return INT2NUM(0);
|
|
770
|
+
break;
|
|
771
|
+
case OPE_COERCE:
|
|
772
|
+
return rb_assoc_new(
|
|
773
|
+
rb_float128_cf128(y),
|
|
774
|
+
rb_float128_cf128(x));
|
|
775
|
+
break;
|
|
776
|
+
default:
|
|
777
|
+
unknown_opecode();
|
|
778
|
+
return rb_float128_cf128(0.q);
|
|
779
|
+
break;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
static VALUE
|
|
784
|
+
float128_ope_float(VALUE self, VALUE other, int ope)
|
|
785
|
+
{
|
|
786
|
+
__float128 x = GetF128(self);
|
|
787
|
+
__float128 y = (__float128)NUM2DBL(other);
|
|
788
|
+
|
|
789
|
+
switch (ope) {
|
|
790
|
+
case OPE_ADD:
|
|
791
|
+
return rb_float128_cf128(x + y);
|
|
792
|
+
break;
|
|
793
|
+
case OPE_SUB:
|
|
794
|
+
return rb_float128_cf128(x - y);
|
|
795
|
+
break;
|
|
796
|
+
case OPE_MUL:
|
|
797
|
+
return rb_float128_cf128(x * y);
|
|
798
|
+
break;
|
|
799
|
+
case OPE_DIV:
|
|
800
|
+
return rb_float128_cf128(x / y);
|
|
801
|
+
break;
|
|
802
|
+
case OPE_MOD:
|
|
803
|
+
return rb_float128_cf128(f128_modulo(x, y));
|
|
804
|
+
break;
|
|
805
|
+
case OPE_POW:
|
|
806
|
+
return rb_float128_cf128(powq(x, y));
|
|
807
|
+
break;
|
|
808
|
+
case OPE_CMP:
|
|
809
|
+
if (isnanq(x) || isnanq(y))
|
|
810
|
+
return Qnil;
|
|
811
|
+
else if (x < y)
|
|
812
|
+
return INT2NUM(-1);
|
|
813
|
+
else if (x > y)
|
|
814
|
+
return INT2NUM( 1);
|
|
815
|
+
else /* (x == y) */
|
|
816
|
+
return INT2NUM( 0);
|
|
817
|
+
break;
|
|
818
|
+
case OPE_COERCE:
|
|
819
|
+
return rb_assoc_new(
|
|
820
|
+
rb_float128_cf128(y),
|
|
821
|
+
rb_float128_cf128(x));
|
|
822
|
+
break;
|
|
823
|
+
default:
|
|
824
|
+
unknown_opecode();
|
|
825
|
+
return rb_float128_cf128(0.q);
|
|
826
|
+
break;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
static VALUE
|
|
831
|
+
float128_ope_float128(VALUE self, VALUE other, int ope)
|
|
832
|
+
{
|
|
833
|
+
__float128 x = GetF128(self);
|
|
834
|
+
__float128 y = GetF128(other);
|
|
835
|
+
|
|
836
|
+
switch (ope) {
|
|
837
|
+
case OPE_ADD:
|
|
838
|
+
return rb_float128_cf128(x + y);
|
|
839
|
+
break;
|
|
840
|
+
case OPE_SUB:
|
|
841
|
+
return rb_float128_cf128(x - y);
|
|
842
|
+
break;
|
|
843
|
+
case OPE_MUL:
|
|
844
|
+
return rb_float128_cf128(x * y);
|
|
845
|
+
break;
|
|
846
|
+
case OPE_DIV:
|
|
847
|
+
return rb_float128_cf128(x / y);
|
|
848
|
+
break;
|
|
849
|
+
case OPE_MOD:
|
|
850
|
+
return rb_float128_cf128(f128_modulo(x, y));
|
|
851
|
+
break;
|
|
852
|
+
case OPE_POW:
|
|
853
|
+
return rb_float128_cf128(powq(x, y));
|
|
854
|
+
break;
|
|
855
|
+
case OPE_CMP:
|
|
856
|
+
if (isnanq(x) || isnanq(y))
|
|
857
|
+
return Qnil;
|
|
858
|
+
else if (x < y)
|
|
859
|
+
return INT2NUM(-1);
|
|
860
|
+
else if (x > y)
|
|
861
|
+
return INT2NUM( 1);
|
|
862
|
+
else /* (x == y) */
|
|
863
|
+
return INT2NUM( 0);
|
|
864
|
+
break;
|
|
865
|
+
case OPE_COERCE:
|
|
866
|
+
return rb_assoc_new(
|
|
867
|
+
rb_float128_cf128(y),
|
|
868
|
+
rb_float128_cf128(x));
|
|
869
|
+
break;
|
|
870
|
+
default:
|
|
871
|
+
unknown_opecode();
|
|
872
|
+
return rb_float128_cf128(0.q);
|
|
873
|
+
break;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
VALUE
|
|
878
|
+
float128_nucomp_pow(VALUE x, VALUE y)
|
|
879
|
+
{
|
|
880
|
+
if (RTEST(rb_num_coerce_cmp(INT2FIX(0), rb_complex_imag(y), rb_intern("=="))))
|
|
881
|
+
{
|
|
882
|
+
__float128 x_real = GetF128(x);
|
|
883
|
+
__float128 y_real = get_real(rb_complex_real(y));
|
|
884
|
+
__float128 z_real = powq(x_real, y_real);
|
|
885
|
+
return rb_Complex(rb_float128_cf128(z_real), rb_complex_imag(y));
|
|
886
|
+
}
|
|
887
|
+
else
|
|
888
|
+
{
|
|
889
|
+
__float128 x_real = GetF128(x);
|
|
890
|
+
#if 0
|
|
891
|
+
__float128 y_real = get_real(rb_complex_real(y));
|
|
892
|
+
__float128 y_imag = get_real(rb_complex_imag(y));
|
|
893
|
+
__float128 z_real = powq(x_real, y_real) * cosq(y_imag * logq(x_real));
|
|
894
|
+
__float128 z_imag = powq(x_real, y_real) * sinq(y_imag * logq(x_real));
|
|
895
|
+
return rb_Complex(rb_float128_cf128(z_real), rb_float128_cf128(z_imag));
|
|
896
|
+
#else
|
|
897
|
+
__complex128 z;
|
|
898
|
+
__real__ z = get_real(rb_complex_real(y));
|
|
899
|
+
__imag__ z = get_real(rb_complex_imag(y));
|
|
900
|
+
z = cpowq(x_real, z);
|
|
901
|
+
return rb_Complex(
|
|
902
|
+
rb_float128_cf128(crealq(z)),
|
|
903
|
+
rb_float128_cf128(cimagq(z)));
|
|
904
|
+
#endif
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
static VALUE
|
|
909
|
+
float128_ope_nucomp(VALUE self, VALUE other, int ope)
|
|
910
|
+
{
|
|
911
|
+
VALUE x = rb_Complex1(self);
|
|
912
|
+
VALUE y = other;
|
|
913
|
+
switch (ope) {
|
|
914
|
+
case OPE_ADD:
|
|
915
|
+
return rb_complex_plus(x, y);
|
|
916
|
+
break;
|
|
917
|
+
case OPE_SUB:
|
|
918
|
+
return rb_complex_minus(x, y);
|
|
919
|
+
break;
|
|
920
|
+
case OPE_MUL:
|
|
921
|
+
return rb_complex_mul(x, y);
|
|
922
|
+
break;
|
|
923
|
+
case OPE_DIV:
|
|
924
|
+
return rb_complex_div(x, y);
|
|
925
|
+
break;
|
|
926
|
+
case OPE_MOD:
|
|
927
|
+
// undefined
|
|
928
|
+
return rb_num_coerce_bin(x, y, '%');
|
|
929
|
+
break;
|
|
930
|
+
case OPE_POW:
|
|
931
|
+
return float128_nucomp_pow(self, other);
|
|
932
|
+
break;
|
|
933
|
+
case OPE_CMP:
|
|
934
|
+
return rb_num_coerce_cmp(x, y, rb_intern("<=>"));
|
|
935
|
+
break;
|
|
936
|
+
case OPE_COERCE:
|
|
937
|
+
return rb_assoc_new(y, x);
|
|
938
|
+
break;
|
|
939
|
+
default:
|
|
940
|
+
unknown_opecode();
|
|
941
|
+
return rb_float128_cf128(0.q);
|
|
942
|
+
break;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
static VALUE
|
|
947
|
+
float128_ope_complex128(VALUE self, VALUE other, int ope)
|
|
948
|
+
{
|
|
949
|
+
__float128 x = GetF128(self);
|
|
950
|
+
__complex128 y = rb_complex128_value(other);
|
|
951
|
+
|
|
952
|
+
switch (ope) {
|
|
953
|
+
case OPE_ADD:
|
|
954
|
+
return rb_complex128_cc128(x + y);
|
|
955
|
+
break;
|
|
956
|
+
case OPE_SUB:
|
|
957
|
+
return rb_complex128_cc128(x - y);
|
|
958
|
+
break;
|
|
959
|
+
case OPE_MUL:
|
|
960
|
+
return rb_complex128_cc128(x * y);
|
|
961
|
+
break;
|
|
962
|
+
case OPE_DIV:
|
|
963
|
+
return rb_complex128_cc128(x / y);
|
|
964
|
+
break;
|
|
965
|
+
case OPE_MOD:
|
|
966
|
+
return rb_complex128_cc128(cmodq(x, y));
|
|
967
|
+
break;
|
|
968
|
+
case OPE_POW:
|
|
969
|
+
return rb_complex128_cc128(cpowq(x, y));
|
|
970
|
+
break;
|
|
971
|
+
case OPE_CMP:
|
|
972
|
+
if (isnanq(x) || isnanq(crealq(y)) || (cimagq(y) != 0))
|
|
973
|
+
return Qnil;
|
|
974
|
+
else
|
|
975
|
+
{
|
|
976
|
+
__float128 y_real = crealq(y);
|
|
977
|
+
if (x < y_real)
|
|
978
|
+
return INT2NUM(-1);
|
|
979
|
+
else if (x > y_real)
|
|
980
|
+
return INT2NUM( 1);
|
|
981
|
+
else /* (x == y_real) */
|
|
982
|
+
return INT2NUM( 0);
|
|
983
|
+
}
|
|
984
|
+
break;
|
|
985
|
+
case OPE_COERCE:
|
|
986
|
+
return rb_assoc_new(
|
|
987
|
+
rb_complex128_cc128(y),
|
|
988
|
+
rb_complex128_cc128((__complex128)x));
|
|
989
|
+
break;
|
|
990
|
+
default:
|
|
991
|
+
unknown_opecode();
|
|
992
|
+
return rb_float128_cf128(0.q);
|
|
993
|
+
break;
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
/*
|
|
998
|
+
* call-seq:
|
|
999
|
+
* Float128 + Numeric -> Float128 | Complex128 | Complex
|
|
1000
|
+
*
|
|
1001
|
+
* Adds the right operands.
|
|
1002
|
+
* If the right operand is a real number, it is converted to Float128, and if it is a complex number, it is converted to the Complex class and then operated on.
|
|
1003
|
+
*/
|
|
1004
|
+
static VALUE
|
|
1005
|
+
float128_add(VALUE self, VALUE other)
|
|
1006
|
+
{
|
|
1007
|
+
switch (convertion_num_types(other)) {
|
|
1008
|
+
case NUM_FIXNUM:
|
|
1009
|
+
case NUM_BIGNUM:
|
|
1010
|
+
return float128_ope_integer(self, other, OPE_ADD);
|
|
1011
|
+
break;
|
|
1012
|
+
case NUM_RATIONAL:
|
|
1013
|
+
return float128_ope_rational(self, other, OPE_ADD);
|
|
1014
|
+
break;
|
|
1015
|
+
case NUM_FLOAT:
|
|
1016
|
+
return float128_ope_float(self, other, OPE_ADD);
|
|
1017
|
+
break;
|
|
1018
|
+
case NUM_COMPLEX:
|
|
1019
|
+
return float128_ope_nucomp(self, other, OPE_ADD);
|
|
1020
|
+
break;
|
|
1021
|
+
case NUM_FLOAT128:
|
|
1022
|
+
return float128_ope_float128(self, other, OPE_ADD);
|
|
1023
|
+
break;
|
|
1024
|
+
case NUM_COMPLEX128:
|
|
1025
|
+
case NUM_OTHERTYPE:
|
|
1026
|
+
default:
|
|
1027
|
+
return rb_num_coerce_bin(self, other, '+');
|
|
1028
|
+
break;
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
/*
|
|
1033
|
+
* call-seq:
|
|
1034
|
+
* Float128 - Numeric -> Float128 | Complex128 | Complex
|
|
1035
|
+
*
|
|
1036
|
+
* Subtracts the right operand.
|
|
1037
|
+
* If the right operand is a real number, it is converted to Float128, and if it is a complex number, it is converted to the Complex class and then operated on.
|
|
1038
|
+
*/
|
|
1039
|
+
static VALUE
|
|
1040
|
+
float128_sub(VALUE self, VALUE other)
|
|
1041
|
+
{
|
|
1042
|
+
switch (convertion_num_types(other)) {
|
|
1043
|
+
case NUM_FIXNUM:
|
|
1044
|
+
case NUM_BIGNUM:
|
|
1045
|
+
return float128_ope_integer(self, other, OPE_SUB);
|
|
1046
|
+
break;
|
|
1047
|
+
case NUM_RATIONAL:
|
|
1048
|
+
return float128_ope_rational(self, other, OPE_SUB);
|
|
1049
|
+
break;
|
|
1050
|
+
case NUM_FLOAT:
|
|
1051
|
+
return float128_ope_float(self, other, OPE_SUB);
|
|
1052
|
+
break;
|
|
1053
|
+
case NUM_COMPLEX:
|
|
1054
|
+
return float128_ope_nucomp(self, other, OPE_SUB);
|
|
1055
|
+
break;
|
|
1056
|
+
case NUM_FLOAT128:
|
|
1057
|
+
return float128_ope_float128(self, other, OPE_SUB);
|
|
1058
|
+
break;
|
|
1059
|
+
case NUM_COMPLEX128:
|
|
1060
|
+
case NUM_OTHERTYPE:
|
|
1061
|
+
default:
|
|
1062
|
+
return rb_num_coerce_bin(self, other, '-');
|
|
1063
|
+
break;
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
/*
|
|
1068
|
+
* call-seq:
|
|
1069
|
+
* Float128 * Numeric -> Float128 | Complex128 | Complex
|
|
1070
|
+
*
|
|
1071
|
+
* Multiplies with the right operand.
|
|
1072
|
+
* If the right operand is a real number, it is converted to Float128, and if it is a complex number, it is converted to the Complex class and then operated on.
|
|
1073
|
+
*/
|
|
1074
|
+
static VALUE
|
|
1075
|
+
float128_mul(VALUE self, VALUE other)
|
|
1076
|
+
{
|
|
1077
|
+
switch (convertion_num_types(other)) {
|
|
1078
|
+
case NUM_FIXNUM:
|
|
1079
|
+
case NUM_BIGNUM:
|
|
1080
|
+
return float128_ope_integer(self, other, OPE_MUL);
|
|
1081
|
+
break;
|
|
1082
|
+
case NUM_RATIONAL:
|
|
1083
|
+
return float128_ope_rational(self, other, OPE_MUL);
|
|
1084
|
+
break;
|
|
1085
|
+
case NUM_FLOAT:
|
|
1086
|
+
return float128_ope_float(self, other, OPE_MUL);
|
|
1087
|
+
break;
|
|
1088
|
+
case NUM_COMPLEX:
|
|
1089
|
+
return float128_ope_nucomp(self, other, OPE_MUL);
|
|
1090
|
+
break;
|
|
1091
|
+
case NUM_FLOAT128:
|
|
1092
|
+
return float128_ope_float128(self, other, OPE_MUL);
|
|
1093
|
+
break;
|
|
1094
|
+
case NUM_COMPLEX128:
|
|
1095
|
+
case NUM_OTHERTYPE:
|
|
1096
|
+
default:
|
|
1097
|
+
return rb_num_coerce_bin(self, other, '*');
|
|
1098
|
+
break;
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
/*
|
|
1103
|
+
* call-seq:
|
|
1104
|
+
* Float128 / Numeric -> Float128 | Complex128 | Complex
|
|
1105
|
+
*
|
|
1106
|
+
* Takes the quotient of the right operand.
|
|
1107
|
+
* If the right operand is a real number, it is converted to Float128, and if it is a complex number, it is converted to the Complex class and then operated on.
|
|
1108
|
+
*/
|
|
1109
|
+
static VALUE
|
|
1110
|
+
float128_div(VALUE self, VALUE other)
|
|
1111
|
+
{
|
|
1112
|
+
switch (convertion_num_types(other)) {
|
|
1113
|
+
case NUM_FIXNUM:
|
|
1114
|
+
case NUM_BIGNUM:
|
|
1115
|
+
return float128_ope_integer(self, other, OPE_DIV);
|
|
1116
|
+
break;
|
|
1117
|
+
case NUM_RATIONAL:
|
|
1118
|
+
return float128_ope_rational(self, other, OPE_DIV);
|
|
1119
|
+
break;
|
|
1120
|
+
case NUM_FLOAT:
|
|
1121
|
+
return float128_ope_float(self, other, OPE_DIV);
|
|
1122
|
+
break;
|
|
1123
|
+
case NUM_COMPLEX:
|
|
1124
|
+
return float128_ope_nucomp(self, other, OPE_DIV);
|
|
1125
|
+
break;
|
|
1126
|
+
case NUM_FLOAT128:
|
|
1127
|
+
return float128_ope_float128(self, other, OPE_DIV);
|
|
1128
|
+
break;
|
|
1129
|
+
case NUM_COMPLEX128:
|
|
1130
|
+
case NUM_OTHERTYPE:
|
|
1131
|
+
default:
|
|
1132
|
+
return rb_num_coerce_bin(self, other, '/');
|
|
1133
|
+
break;
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
/*
|
|
1138
|
+
* call-seq:
|
|
1139
|
+
* Float128 % Numeric -> Float128
|
|
1140
|
+
*
|
|
1141
|
+
* Performs modulo calculation with the right operand.
|
|
1142
|
+
* If the operands have the same sign, divide towards zero; if they do not, divide towards negative.
|
|
1143
|
+
*/
|
|
1144
|
+
static VALUE
|
|
1145
|
+
float128_mod(VALUE self, VALUE other)
|
|
1146
|
+
{
|
|
1147
|
+
switch (convertion_num_types(other)) {
|
|
1148
|
+
case NUM_FIXNUM:
|
|
1149
|
+
case NUM_BIGNUM:
|
|
1150
|
+
return float128_ope_integer(self, other, OPE_MOD);
|
|
1151
|
+
break;
|
|
1152
|
+
case NUM_RATIONAL:
|
|
1153
|
+
return float128_ope_rational(self, other, OPE_MOD);
|
|
1154
|
+
break;
|
|
1155
|
+
case NUM_FLOAT:
|
|
1156
|
+
return float128_ope_float(self, other, OPE_MOD);
|
|
1157
|
+
break;
|
|
1158
|
+
case NUM_COMPLEX:
|
|
1159
|
+
return float128_ope_nucomp(self, other, OPE_MOD);
|
|
1160
|
+
break;
|
|
1161
|
+
case NUM_FLOAT128:
|
|
1162
|
+
return float128_ope_float128(self, other, OPE_MOD);
|
|
1163
|
+
break;
|
|
1164
|
+
case NUM_COMPLEX128:
|
|
1165
|
+
case NUM_OTHERTYPE:
|
|
1166
|
+
default:
|
|
1167
|
+
return rb_num_coerce_bin(self, other, '%');
|
|
1168
|
+
break;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
/*
|
|
1173
|
+
* call-seq:
|
|
1174
|
+
* Float128 ** Numeric -> Float128 | Complex128 | Complex
|
|
1175
|
+
*
|
|
1176
|
+
* Exponentiates the right operand.
|
|
1177
|
+
* If the right operand is a real number, it is converted to Float128, and if it is a complex number, it is converted to the Complex class and then operated on. */
|
|
1178
|
+
static VALUE
|
|
1179
|
+
float128_pow(VALUE self, VALUE other)
|
|
1180
|
+
{
|
|
1181
|
+
switch (convertion_num_types(other)) {
|
|
1182
|
+
case NUM_FIXNUM:
|
|
1183
|
+
case NUM_BIGNUM:
|
|
1184
|
+
return float128_ope_integer(self, other, OPE_POW);
|
|
1185
|
+
break;
|
|
1186
|
+
case NUM_RATIONAL:
|
|
1187
|
+
return float128_ope_rational(self, other, OPE_POW);
|
|
1188
|
+
break;
|
|
1189
|
+
case NUM_FLOAT:
|
|
1190
|
+
return float128_ope_float(self, other, OPE_POW);
|
|
1191
|
+
break;
|
|
1192
|
+
case NUM_COMPLEX:
|
|
1193
|
+
return float128_ope_nucomp(self, other, OPE_POW);
|
|
1194
|
+
break;
|
|
1195
|
+
case NUM_FLOAT128:
|
|
1196
|
+
return float128_ope_float128(self, other, OPE_POW);
|
|
1197
|
+
break;
|
|
1198
|
+
case NUM_COMPLEX128:
|
|
1199
|
+
case NUM_OTHERTYPE:
|
|
1200
|
+
default:
|
|
1201
|
+
return rb_num_coerce_bin(self, other, rb_intern("**"));
|
|
1202
|
+
break;
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
/*
|
|
1207
|
+
* call-seq:
|
|
1208
|
+
* Float128 <=> Numeric -> -1 | 0 | 1 | nil
|
|
1209
|
+
*
|
|
1210
|
+
* Compares the operands.
|
|
1211
|
+
* Returns -1 if +other+ is greater than +self+, 0 if they are the same, 1 if they are less than +self+, or nil if the comparison is not possible.
|
|
1212
|
+
*/
|
|
1213
|
+
static VALUE
|
|
1214
|
+
float128_cmp(VALUE self, VALUE other)
|
|
1215
|
+
{
|
|
1216
|
+
switch (convertion_num_types(other)) {
|
|
1217
|
+
case NUM_FIXNUM:
|
|
1218
|
+
case NUM_BIGNUM:
|
|
1219
|
+
return float128_ope_integer(self, other, OPE_CMP);
|
|
1220
|
+
break;
|
|
1221
|
+
case NUM_RATIONAL:
|
|
1222
|
+
return float128_ope_rational(self, other, OPE_CMP);
|
|
1223
|
+
break;
|
|
1224
|
+
case NUM_FLOAT:
|
|
1225
|
+
return float128_ope_float(self, other, OPE_CMP);
|
|
1226
|
+
break;
|
|
1227
|
+
case NUM_COMPLEX:
|
|
1228
|
+
return float128_ope_nucomp(self, other, OPE_CMP);
|
|
1229
|
+
break;
|
|
1230
|
+
case NUM_FLOAT128:
|
|
1231
|
+
return float128_ope_float128(self, other, OPE_CMP);
|
|
1232
|
+
break;
|
|
1233
|
+
case NUM_COMPLEX128:
|
|
1234
|
+
return float128_ope_complex128(self, other, OPE_CMP);
|
|
1235
|
+
break;
|
|
1236
|
+
case NUM_OTHERTYPE:
|
|
1237
|
+
default:
|
|
1238
|
+
return rb_num_coerce_cmp(self, other, rb_intern("<=>"));
|
|
1239
|
+
break;
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
/*
|
|
1244
|
+
* call-seq:
|
|
1245
|
+
* coerce(other) -> [other, self]
|
|
1246
|
+
*
|
|
1247
|
+
* It sets +other+ equal to +self+, converts it to an array of pairs [other, self], and returns it.
|
|
1248
|
+
*
|
|
1249
|
+
* 1.0.coerce(Float128::MAX).all?(Float) # => true
|
|
1250
|
+
* 1.0.to_f128.coerce(Float::MAX).all?(Float128) # => true
|
|
1251
|
+
*/
|
|
1252
|
+
static VALUE
|
|
1253
|
+
float128_coerce(int argc, VALUE *argv, VALUE self)
|
|
1254
|
+
{
|
|
1255
|
+
VALUE other;
|
|
1256
|
+
rb_scan_args(argc, argv, "10", &other);
|
|
1257
|
+
switch (convertion_num_types(other)) {
|
|
1258
|
+
case NUM_FIXNUM:
|
|
1259
|
+
case NUM_BIGNUM:
|
|
1260
|
+
return float128_ope_integer(self, other, OPE_COERCE);
|
|
1261
|
+
break;
|
|
1262
|
+
case NUM_RATIONAL:
|
|
1263
|
+
return float128_ope_rational(self, other, OPE_COERCE);
|
|
1264
|
+
break;
|
|
1265
|
+
case NUM_FLOAT:
|
|
1266
|
+
return float128_ope_float(self, other, OPE_COERCE);
|
|
1267
|
+
break;
|
|
1268
|
+
case NUM_COMPLEX:
|
|
1269
|
+
return float128_ope_nucomp(self, other, OPE_COERCE);
|
|
1270
|
+
break;
|
|
1271
|
+
case NUM_FLOAT128:
|
|
1272
|
+
return float128_ope_float128(self, other, OPE_COERCE);
|
|
1273
|
+
break;
|
|
1274
|
+
case NUM_COMPLEX128:
|
|
1275
|
+
return float128_ope_complex128(self, other, OPE_COERCE);
|
|
1276
|
+
break;
|
|
1277
|
+
case NUM_OTHERTYPE:
|
|
1278
|
+
default:
|
|
1279
|
+
return rb_call_super(argc, argv);
|
|
1280
|
+
break;
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
static VALUE
|
|
1285
|
+
float128_fused_multiply_add(VALUE xhs, VALUE yhs, VALUE zhs)
|
|
1286
|
+
{
|
|
1287
|
+
__float128 x = get_real(xhs),
|
|
1288
|
+
y = get_real(yhs),
|
|
1289
|
+
z = get_real(zhs);
|
|
1290
|
+
|
|
1291
|
+
return rb_float128_cf128(fmaq(x, y, z));
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
/*
|
|
1295
|
+
* call-seq:
|
|
1296
|
+
* Float128.fma(x, y, z) -> Float128
|
|
1297
|
+
*
|
|
1298
|
+
* Uses fused multiply-add algorithm to efficiently compute x*y+z.
|
|
1299
|
+
* It often produces more accurate results than mathematical calculations.
|
|
1300
|
+
* The arguments are considered to be quadruple-precision floating point numbers.
|
|
1301
|
+
* If this is not possible, an implicit type conversion will be attempted, and if conversion is not possible, a TypeError will be raised.
|
|
1302
|
+
*
|
|
1303
|
+
* Float128.fma(1/3r, 2/3r, 3/3r) # => 1.2222222222222222222222222222222
|
|
1304
|
+
* # 精度の違い
|
|
1305
|
+
* Float128.fma(1.1, 1.2, 1.3) # => 2.6200000000000001021405182655144
|
|
1306
|
+
* Float128.fma('1.1'.to_f128, '1.2'.to_f128, '1.3'.to_f128) # => 2.62
|
|
1307
|
+
*/
|
|
1308
|
+
static VALUE
|
|
1309
|
+
float128_s_fma(int argc, VALUE *argv, VALUE self)
|
|
1310
|
+
{
|
|
1311
|
+
VALUE xhs, yhs, zhs;
|
|
1312
|
+
rb_scan_args(argc, argv, "30", &xhs, &yhs, &zhs);
|
|
1313
|
+
|
|
1314
|
+
return float128_fused_multiply_add(xhs, yhs, zhs);
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
static VALUE
|
|
1318
|
+
float128_sincos(VALUE xhs)
|
|
1319
|
+
{
|
|
1320
|
+
__float128 x = get_real(xhs), sin, cos;
|
|
1321
|
+
sincosq(x, &sin, &cos);
|
|
1322
|
+
return rb_assoc_new( rb_float128_cf128(sin), rb_float128_cf128(cos) );
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
/*
|
|
1326
|
+
* call-seq:
|
|
1327
|
+
* Float128.sincos(x) -> [Float128, Float128]
|
|
1328
|
+
*
|
|
1329
|
+
* Returns an array of sines and cosines of x.
|
|
1330
|
+
* The arguments are considered to be quadruple-precision floating point numbers.
|
|
1331
|
+
* If this is not possible, an implicit type conversion will be attempted, and if conversion is not possible, a TypeError will be raised.
|
|
1332
|
+
*
|
|
1333
|
+
* Float128.sincos(2) # => [0.909297426825681695396019865911745, -0.416146836547142386997568229500762]
|
|
1334
|
+
*/
|
|
1335
|
+
static VALUE
|
|
1336
|
+
float128_s_sincos(int argc, VALUE *argv, VALUE self)
|
|
1337
|
+
{
|
|
1338
|
+
VALUE xhs;
|
|
1339
|
+
rb_scan_args(argc, argv, "10", &xhs);
|
|
1340
|
+
|
|
1341
|
+
return float128_sincos(xhs);
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
static VALUE
|
|
1345
|
+
float128_fmin(VALUE lhs, VALUE rhs)
|
|
1346
|
+
{
|
|
1347
|
+
__float128 l = get_real(lhs), r = get_real(rhs);
|
|
1348
|
+
return rb_float128_cf128(fminq(l, r));
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
/*
|
|
1352
|
+
* call-seq:
|
|
1353
|
+
* Float128.fmin(l, r) -> Float128
|
|
1354
|
+
*
|
|
1355
|
+
* 引数+l+と+r+を比べて小さいほうを返す.
|
|
1356
|
+
* The arguments are considered to be quadruple-precision floating point numbers.
|
|
1357
|
+
* If this is not possible, an implicit type conversion will be attempted, and if conversion is not possible, a TypeError will be raised.
|
|
1358
|
+
*
|
|
1359
|
+
* Float128.fmin(1.23r, 4.56r) # => 1.23
|
|
1360
|
+
* # 二倍精度と四倍精度の同値を比較
|
|
1361
|
+
* Float128.fmin(1.1r, 1.1r) # => 1.1
|
|
1362
|
+
* Float128.fmin(-1.1r, -1.1) # => -1.1000000000000000888178419700125
|
|
1363
|
+
*/
|
|
1364
|
+
static VALUE
|
|
1365
|
+
float128_s_fmin(int argc, VALUE *argv, VALUE self)
|
|
1366
|
+
{
|
|
1367
|
+
VALUE lhs, rhs;
|
|
1368
|
+
rb_scan_args(argc, argv, "20", &lhs, &rhs);
|
|
1369
|
+
|
|
1370
|
+
return float128_fmin(lhs, rhs);
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
static VALUE
|
|
1374
|
+
float128_fmax(VALUE lhs, VALUE rhs)
|
|
1375
|
+
{
|
|
1376
|
+
__float128 l = get_real(lhs), r = get_real(rhs);
|
|
1377
|
+
return rb_float128_cf128(fmaxq(l, r));
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
/*
|
|
1381
|
+
* call-seq:
|
|
1382
|
+
* Float128.fmax(l, r) -> Float128
|
|
1383
|
+
*
|
|
1384
|
+
* 引数+l+と+r+を比べて大きいほうを返す.
|
|
1385
|
+
* The arguments are considered to be quadruple-precision floating point numbers.
|
|
1386
|
+
* If this is not possible, an implicit type conversion will be attempted, and if conversion is not possible, a TypeError will be raised.
|
|
1387
|
+
*
|
|
1388
|
+
* Float128.fmax(1.23r, 4.56r) # => 4.56
|
|
1389
|
+
* # 二倍精度と四倍精度の同値を比較
|
|
1390
|
+
* Float128.fmax(1.1r, 1.1r) # => 1.1000000000000000888178419700125
|
|
1391
|
+
* Float128.fmax(-1.1r, -1.1) # => -1.1
|
|
1392
|
+
*/
|
|
1393
|
+
static VALUE
|
|
1394
|
+
float128_s_fmax(int argc, VALUE *argv, VALUE self)
|
|
1395
|
+
{
|
|
1396
|
+
VALUE lhs, rhs;
|
|
1397
|
+
rb_scan_args(argc, argv, "20", &lhs, &rhs);
|
|
1398
|
+
|
|
1399
|
+
return float128_fmax(lhs, rhs);
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
/*
|
|
1403
|
+
* call-seq:
|
|
1404
|
+
* Float128.ldexp(x, exp) -> Float128
|
|
1405
|
+
*
|
|
1406
|
+
* xに2のexp乗をかけた値を返す(Load Exponent).Mathモジュールにも同名関数があるが,返却値は四倍精度である.
|
|
1407
|
+
* frexpで分解した指数と仮数をもとの数値に戻すのに使う.
|
|
1408
|
+
*
|
|
1409
|
+
* fra, exp = '2.2'.to_f128.frexp # => [0.55, 2]
|
|
1410
|
+
* Float128.ldexp(fra, exp) # => 2.2
|
|
1411
|
+
*/
|
|
1412
|
+
static VALUE
|
|
1413
|
+
float128_s_ldexp(VALUE obj, VALUE x, VALUE exp)
|
|
1414
|
+
{
|
|
1415
|
+
__float128 v_x = get_real(x);
|
|
1416
|
+
int v_exp = NUM2INT(exp);
|
|
1417
|
+
|
|
1418
|
+
return rb_float128_cf128(ldexpq(v_x, v_exp));
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
/*
|
|
1422
|
+
* call-seq:
|
|
1423
|
+
* Float128.scalb(x, n) -> Float128
|
|
1424
|
+
* Float128.scalbn(x, n) -> Float128
|
|
1425
|
+
*
|
|
1426
|
+
* xにFloat::RADIXのn乗をかけた値を返す.返却値は四倍精度である.
|
|
1427
|
+
* メソッド名はC/C++の策定のときのオリジナルだが,(もちろん)newの意味を持つnが付け加えられたaliasもある.
|
|
1428
|
+
* 内部的にはnがlong型パージョンなscalblnq()を使用する.
|
|
1429
|
+
*
|
|
1430
|
+
* # 3.0 * Float::RADIX ** 4
|
|
1431
|
+
* Float128.scalb(3, 4) # => 48.0
|
|
1432
|
+
*/
|
|
1433
|
+
static VALUE
|
|
1434
|
+
float128_s_scalb(VALUE obj, VALUE x, VALUE exp)
|
|
1435
|
+
{
|
|
1436
|
+
__float128 v_x = get_real(x);
|
|
1437
|
+
long v_exp = NUM2LONG(exp);
|
|
1438
|
+
|
|
1439
|
+
return rb_float128_cf128(scalblnq(v_x, v_exp));
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
|
|
1443
|
+
/*
|
|
1444
|
+
* call-seq:
|
|
1445
|
+
* polar -> [Float128, Float128]
|
|
1446
|
+
*
|
|
1447
|
+
* +self+の絶対値と偏角を配列にして返す.成分はいずれもFloat128である.
|
|
1448
|
+
*
|
|
1449
|
+
* Complex128.polar(1, 2).polar # => [1, 2]
|
|
1450
|
+
*/
|
|
1451
|
+
static VALUE
|
|
1452
|
+
complex128_polar(VALUE self)
|
|
1453
|
+
{
|
|
1454
|
+
__complex128 c128 = GetC128(self);
|
|
1455
|
+
|
|
1456
|
+
return rb_assoc_new(
|
|
1457
|
+
rb_float128_cf128(cabsq(c128)),
|
|
1458
|
+
rb_float128_cf128(cargq(c128)));
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
/*
|
|
1462
|
+
* call-seq:
|
|
1463
|
+
* abs -> Float128
|
|
1464
|
+
* magnitude -> Float128
|
|
1465
|
+
*
|
|
1466
|
+
* +self+の絶対値を返す.
|
|
1467
|
+
*/
|
|
1468
|
+
static VALUE
|
|
1469
|
+
complex128_abs(VALUE self)
|
|
1470
|
+
{
|
|
1471
|
+
__complex128 c128 = GetC128(self);
|
|
1472
|
+
|
|
1473
|
+
return rb_float128_cf128(cabsq(c128));
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
/*
|
|
1477
|
+
* call-seq:
|
|
1478
|
+
* abs2 -> Float128
|
|
1479
|
+
*
|
|
1480
|
+
* +self+の絶対値の二乗を返す.
|
|
1481
|
+
*/
|
|
1482
|
+
static VALUE
|
|
1483
|
+
complex128_abs2(VALUE self)
|
|
1484
|
+
{
|
|
1485
|
+
__complex128 c128 = GetC128(self);
|
|
1486
|
+
__float128 abs_val = cabsq(c128);
|
|
1487
|
+
|
|
1488
|
+
return rb_float128_cf128(abs_val * abs_val);
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
/*
|
|
1492
|
+
* call-seq:
|
|
1493
|
+
* arg -> Float128
|
|
1494
|
+
* angle -> Float128
|
|
1495
|
+
* phase -> Float128
|
|
1496
|
+
*
|
|
1497
|
+
* +self+の偏角を[-π,π]の範囲で返す.
|
|
1498
|
+
*/
|
|
1499
|
+
static VALUE
|
|
1500
|
+
complex128_arg(VALUE self)
|
|
1501
|
+
{
|
|
1502
|
+
__complex128 c128 = GetC128(self);
|
|
1503
|
+
|
|
1504
|
+
return rb_float128_cf128(cargq(c128));
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
/*
|
|
1508
|
+
* call-seq:
|
|
1509
|
+
* conj -> Complex128
|
|
1510
|
+
*
|
|
1511
|
+
* +self+の共役複素数を返す.
|
|
1512
|
+
*/
|
|
1513
|
+
static VALUE
|
|
1514
|
+
complex128_conj(VALUE self)
|
|
1515
|
+
{
|
|
1516
|
+
__complex128 c128 = GetC128(self);
|
|
1517
|
+
|
|
1518
|
+
return rb_complex128_cc128(conjq(c128));
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
static VALUE
|
|
1522
|
+
complex128_ope_integer(VALUE self, VALUE other, int ope)
|
|
1523
|
+
{
|
|
1524
|
+
__complex128 z = GetC128(self);
|
|
1525
|
+
__float128 w = integer_to_cf128(other);
|
|
1526
|
+
|
|
1527
|
+
switch (ope) {
|
|
1528
|
+
case OPE_ADD:
|
|
1529
|
+
return rb_complex128_cc128(z + w);
|
|
1530
|
+
break;
|
|
1531
|
+
case OPE_SUB:
|
|
1532
|
+
return rb_complex128_cc128(z - w);
|
|
1533
|
+
break;
|
|
1534
|
+
case OPE_MUL:
|
|
1535
|
+
return rb_complex128_cc128(z * w);
|
|
1536
|
+
break;
|
|
1537
|
+
case OPE_DIV:
|
|
1538
|
+
return rb_complex128_cc128(z / w);
|
|
1539
|
+
break;
|
|
1540
|
+
case OPE_MOD:
|
|
1541
|
+
return rb_complex128_cc128(cmodq(z, w));
|
|
1542
|
+
break;
|
|
1543
|
+
case OPE_POW:
|
|
1544
|
+
return rb_complex128_cc128(cpowq(z, w));
|
|
1545
|
+
break;
|
|
1546
|
+
case OPE_CMP:
|
|
1547
|
+
__float128 z_real = crealq(z);
|
|
1548
|
+
if (isnanq(z_real) || cimagq(z) != 0)
|
|
1549
|
+
return Qnil;
|
|
1550
|
+
else if (z_real < w)
|
|
1551
|
+
return INT2NUM(-1);
|
|
1552
|
+
else if (z_real > w)
|
|
1553
|
+
return INT2NUM(1);
|
|
1554
|
+
else /* (z_real == w) */
|
|
1555
|
+
return INT2NUM(0);
|
|
1556
|
+
break;
|
|
1557
|
+
case OPE_COERCE:
|
|
1558
|
+
return rb_assoc_new(
|
|
1559
|
+
rb_complex128_cc128(w),
|
|
1560
|
+
rb_complex128_cc128(z));
|
|
1561
|
+
break;
|
|
1562
|
+
default:
|
|
1563
|
+
unknown_opecode();
|
|
1564
|
+
return rb_complex128_cc128(0+0i);
|
|
1565
|
+
break;
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
static VALUE
|
|
1570
|
+
complex128_ope_rational(VALUE self, VALUE other, int ope)
|
|
1571
|
+
{
|
|
1572
|
+
__complex128 z = GetC128(self);
|
|
1573
|
+
__float128 w = rational_to_cf128(other);
|
|
1574
|
+
|
|
1575
|
+
switch (ope) {
|
|
1576
|
+
case OPE_ADD:
|
|
1577
|
+
return rb_complex128_cc128(z + w);
|
|
1578
|
+
break;
|
|
1579
|
+
case OPE_SUB:
|
|
1580
|
+
return rb_complex128_cc128(z - w);
|
|
1581
|
+
break;
|
|
1582
|
+
case OPE_MUL:
|
|
1583
|
+
return rb_complex128_cc128(z * w);
|
|
1584
|
+
break;
|
|
1585
|
+
case OPE_DIV:
|
|
1586
|
+
return rb_complex128_cc128(z / w);
|
|
1587
|
+
break;
|
|
1588
|
+
case OPE_MOD:
|
|
1589
|
+
return rb_complex128_cc128(cmodq(z, w));
|
|
1590
|
+
break;
|
|
1591
|
+
case OPE_POW:
|
|
1592
|
+
return rb_complex128_cc128(cpowq(z, w));
|
|
1593
|
+
break;
|
|
1594
|
+
case OPE_CMP:
|
|
1595
|
+
__float128 z_real = crealq(z);
|
|
1596
|
+
if (isnanq(z_real) || cimagq(z) != 0)
|
|
1597
|
+
return Qnil;
|
|
1598
|
+
else if (z_real < w)
|
|
1599
|
+
return INT2NUM(-1);
|
|
1600
|
+
else if (z_real > w)
|
|
1601
|
+
return INT2NUM(1);
|
|
1602
|
+
else /* (z_real == w) */
|
|
1603
|
+
return INT2NUM(0);
|
|
1604
|
+
break;
|
|
1605
|
+
case OPE_COERCE:
|
|
1606
|
+
return rb_assoc_new(
|
|
1607
|
+
rb_complex128_cc128(w),
|
|
1608
|
+
rb_complex128_cc128(z));
|
|
1609
|
+
break;
|
|
1610
|
+
default:
|
|
1611
|
+
unknown_opecode();
|
|
1612
|
+
return rb_complex128_cc128(0+0i);
|
|
1613
|
+
break;
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
static VALUE
|
|
1618
|
+
complex128_ope_float(VALUE self, VALUE other, int ope)
|
|
1619
|
+
{
|
|
1620
|
+
__complex128 z = GetC128(self);
|
|
1621
|
+
__float128 w = (__float128)NUM2DBL(other);
|
|
1622
|
+
|
|
1623
|
+
switch (ope) {
|
|
1624
|
+
case OPE_ADD:
|
|
1625
|
+
return rb_complex128_cc128(z + w);
|
|
1626
|
+
break;
|
|
1627
|
+
case OPE_SUB:
|
|
1628
|
+
return rb_complex128_cc128(z - w);
|
|
1629
|
+
break;
|
|
1630
|
+
case OPE_MUL:
|
|
1631
|
+
return rb_complex128_cc128(z * w);
|
|
1632
|
+
break;
|
|
1633
|
+
case OPE_DIV:
|
|
1634
|
+
return rb_complex128_cc128(z / w);
|
|
1635
|
+
break;
|
|
1636
|
+
case OPE_MOD:
|
|
1637
|
+
return rb_complex128_cc128(cmodq(z, w));
|
|
1638
|
+
break;
|
|
1639
|
+
case OPE_POW:
|
|
1640
|
+
return rb_complex128_cc128(cpowq(z, w));
|
|
1641
|
+
break;
|
|
1642
|
+
case OPE_CMP:
|
|
1643
|
+
__float128 z_real = crealq(z);
|
|
1644
|
+
if (isnanq(z_real) || isnanq(w) || cimagq(z) != 0)
|
|
1645
|
+
return Qnil;
|
|
1646
|
+
else if (z_real < w)
|
|
1647
|
+
return INT2NUM(-1);
|
|
1648
|
+
else if (z_real > w)
|
|
1649
|
+
return INT2NUM(1);
|
|
1650
|
+
else /* (z_real == w) */
|
|
1651
|
+
return INT2NUM(0);
|
|
1652
|
+
break;
|
|
1653
|
+
case OPE_COERCE:
|
|
1654
|
+
return rb_assoc_new(
|
|
1655
|
+
rb_complex128_cc128(w),
|
|
1656
|
+
rb_complex128_cc128(z));
|
|
1657
|
+
break;
|
|
1658
|
+
default:
|
|
1659
|
+
unknown_opecode();
|
|
1660
|
+
return rb_complex128_cc128(0+0i);
|
|
1661
|
+
break;
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
static VALUE
|
|
1666
|
+
complex128_ope_float128(VALUE self, VALUE other, int ope)
|
|
1667
|
+
{
|
|
1668
|
+
__complex128 z = GetC128(self);
|
|
1669
|
+
__float128 w = GetF128(other);
|
|
1670
|
+
|
|
1671
|
+
switch (ope) {
|
|
1672
|
+
case OPE_ADD:
|
|
1673
|
+
return rb_complex128_cc128(z + w);
|
|
1674
|
+
break;
|
|
1675
|
+
case OPE_SUB:
|
|
1676
|
+
return rb_complex128_cc128(z - w);
|
|
1677
|
+
break;
|
|
1678
|
+
case OPE_MUL:
|
|
1679
|
+
return rb_complex128_cc128(z * w);
|
|
1680
|
+
break;
|
|
1681
|
+
case OPE_DIV:
|
|
1682
|
+
return rb_complex128_cc128(z / w);
|
|
1683
|
+
break;
|
|
1684
|
+
case OPE_MOD:
|
|
1685
|
+
return rb_complex128_cc128(cmodq(z, w));
|
|
1686
|
+
break;
|
|
1687
|
+
case OPE_POW:
|
|
1688
|
+
return rb_complex128_cc128(cpowq(z, w));
|
|
1689
|
+
break;
|
|
1690
|
+
case OPE_CMP:
|
|
1691
|
+
__float128 z_real = crealq(z);
|
|
1692
|
+
if (isnanq(z_real) || isnanq(w) || cimagq(z) != 0)
|
|
1693
|
+
return Qnil;
|
|
1694
|
+
else if (z_real < w)
|
|
1695
|
+
return INT2NUM(-1);
|
|
1696
|
+
else if (z_real > w)
|
|
1697
|
+
return INT2NUM(1);
|
|
1698
|
+
else /* (z_real == w) */
|
|
1699
|
+
return INT2NUM(0);
|
|
1700
|
+
break;
|
|
1701
|
+
case OPE_COERCE:
|
|
1702
|
+
return rb_assoc_new(
|
|
1703
|
+
rb_complex128_cc128(w),
|
|
1704
|
+
rb_complex128_cc128(z));
|
|
1705
|
+
break;
|
|
1706
|
+
default:
|
|
1707
|
+
unknown_opecode();
|
|
1708
|
+
return rb_complex128_cc128(0+0i);
|
|
1709
|
+
break;
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
VALUE
|
|
1714
|
+
complex128_nucomp_mod(VALUE z, VALUE w)
|
|
1715
|
+
{
|
|
1716
|
+
return rb_Complex1(INT2FIX(0)); // 未定義
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
VALUE
|
|
1720
|
+
complex128_nucomp_pow(VALUE z, VALUE w)
|
|
1721
|
+
{
|
|
1722
|
+
__complex128 z_value = GetC128(z);
|
|
1723
|
+
__complex128 w_value;
|
|
1724
|
+
__real__ w_value = get_real(rb_complex_real(w));
|
|
1725
|
+
__imag__ w_value = get_real(rb_complex_imag(w));
|
|
1726
|
+
__complex128 c = cpowq(z_value, w_value);
|
|
1727
|
+
return rb_Complex(
|
|
1728
|
+
rb_float128_cf128(crealq(c)),
|
|
1729
|
+
rb_float128_cf128(cimagq(c)));
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
static VALUE
|
|
1733
|
+
complex128_ope_nucomp(VALUE self, VALUE other, int ope)
|
|
1734
|
+
{
|
|
1735
|
+
__complex128 c128 = GetC128(self);
|
|
1736
|
+
VALUE x = rb_Complex(
|
|
1737
|
+
rb_float128_cf128(crealq(c128)),
|
|
1738
|
+
rb_float128_cf128(cimagq(c128)));
|
|
1739
|
+
VALUE y = other;
|
|
1740
|
+
switch (ope) {
|
|
1741
|
+
case OPE_ADD:
|
|
1742
|
+
return rb_complex_plus(x, y);
|
|
1743
|
+
break;
|
|
1744
|
+
case OPE_SUB:
|
|
1745
|
+
return rb_complex_minus(x, y);
|
|
1746
|
+
break;
|
|
1747
|
+
case OPE_MUL:
|
|
1748
|
+
return rb_complex_mul(x, y);
|
|
1749
|
+
break;
|
|
1750
|
+
case OPE_DIV:
|
|
1751
|
+
return rb_complex_div(x, y);
|
|
1752
|
+
break;
|
|
1753
|
+
case OPE_MOD:
|
|
1754
|
+
return complex128_nucomp_mod(self, other);
|
|
1755
|
+
break;
|
|
1756
|
+
case OPE_POW:
|
|
1757
|
+
return complex128_nucomp_pow(self, other);
|
|
1758
|
+
break;
|
|
1759
|
+
case OPE_CMP:
|
|
1760
|
+
return rb_num_coerce_cmp(x, y, rb_intern("<=>"));
|
|
1761
|
+
break;
|
|
1762
|
+
case OPE_COERCE:
|
|
1763
|
+
return rb_assoc_new(y, x);
|
|
1764
|
+
break;
|
|
1765
|
+
default:
|
|
1766
|
+
unknown_opecode();
|
|
1767
|
+
return rb_complex128_cc128(0+0i);
|
|
1768
|
+
break;
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
static VALUE
|
|
1773
|
+
complex128_ope_complex128(VALUE self, VALUE other, int ope)
|
|
1774
|
+
{
|
|
1775
|
+
__complex128 z = GetC128(self);
|
|
1776
|
+
__complex128 w = GetC128(other);
|
|
1777
|
+
|
|
1778
|
+
switch (ope) {
|
|
1779
|
+
case OPE_ADD:
|
|
1780
|
+
return rb_complex128_cc128(z + w);
|
|
1781
|
+
break;
|
|
1782
|
+
case OPE_SUB:
|
|
1783
|
+
return rb_complex128_cc128(z - w);
|
|
1784
|
+
break;
|
|
1785
|
+
case OPE_MUL:
|
|
1786
|
+
return rb_complex128_cc128(z * w);
|
|
1787
|
+
break;
|
|
1788
|
+
case OPE_DIV:
|
|
1789
|
+
return rb_complex128_cc128(z / w);
|
|
1790
|
+
break;
|
|
1791
|
+
case OPE_MOD:
|
|
1792
|
+
return rb_complex128_cc128(cmodq(z, w));
|
|
1793
|
+
break;
|
|
1794
|
+
case OPE_POW:
|
|
1795
|
+
return rb_complex128_cc128(cpowq(z, w));
|
|
1796
|
+
break;
|
|
1797
|
+
case OPE_CMP:
|
|
1798
|
+
__float128 z_real = crealq(z), z_imag = cimagq(z);
|
|
1799
|
+
__float128 w_real = crealq(z), w_imag = cimagq(z);
|
|
1800
|
+
if (isnanq(z_real) || isnanq(z_imag) ||
|
|
1801
|
+
isnanq(w_real) || isnanq(w_imag) ||
|
|
1802
|
+
z_imag != 0 || w_imag != 0)
|
|
1803
|
+
return Qnil;
|
|
1804
|
+
else
|
|
1805
|
+
{
|
|
1806
|
+
if (z_real < w_real)
|
|
1807
|
+
return INT2NUM(-1);
|
|
1808
|
+
else if (z_real > w_real)
|
|
1809
|
+
return INT2NUM( 1);
|
|
1810
|
+
else /* (z_real == w_real) */
|
|
1811
|
+
return INT2NUM( 0);
|
|
1812
|
+
}
|
|
1813
|
+
break;
|
|
1814
|
+
case OPE_COERCE:
|
|
1815
|
+
return rb_assoc_new(other, self);
|
|
1816
|
+
break;
|
|
1817
|
+
default:
|
|
1818
|
+
unknown_opecode();
|
|
1819
|
+
return rb_complex128_cc128(0+0i);
|
|
1820
|
+
break;
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
|
|
1825
|
+
|
|
1826
|
+
/*
|
|
1827
|
+
* call-seq:
|
|
1828
|
+
* Complex128 + Numeric -> Complex128 | Complex
|
|
1829
|
+
*
|
|
1830
|
+
* 右オペランドを加算する.
|
|
1831
|
+
* 右オペランドがComplexクラスであればComplexクラスを,そのほかはComplex128クラスを返却値にそれぞれ演算する.
|
|
1832
|
+
*/
|
|
1833
|
+
static VALUE
|
|
1834
|
+
complex128_add(VALUE self, VALUE other)
|
|
1835
|
+
{
|
|
1836
|
+
switch (convertion_num_types(other)) {
|
|
1837
|
+
case NUM_FIXNUM:
|
|
1838
|
+
case NUM_BIGNUM:
|
|
1839
|
+
return complex128_ope_integer(self, other, OPE_ADD);
|
|
1840
|
+
break;
|
|
1841
|
+
case NUM_RATIONAL:
|
|
1842
|
+
return complex128_ope_rational(self, other, OPE_ADD);
|
|
1843
|
+
break;
|
|
1844
|
+
case NUM_FLOAT:
|
|
1845
|
+
return complex128_ope_float(self, other, OPE_ADD);
|
|
1846
|
+
break;
|
|
1847
|
+
case NUM_COMPLEX:
|
|
1848
|
+
return complex128_ope_nucomp(self, other, OPE_ADD);
|
|
1849
|
+
break;
|
|
1850
|
+
case NUM_FLOAT128:
|
|
1851
|
+
return complex128_ope_float128(self, other, OPE_ADD);
|
|
1852
|
+
break;
|
|
1853
|
+
case NUM_COMPLEX128:
|
|
1854
|
+
return complex128_ope_complex128(self, other, OPE_ADD);
|
|
1855
|
+
break;
|
|
1856
|
+
case NUM_OTHERTYPE:
|
|
1857
|
+
default:
|
|
1858
|
+
return rb_num_coerce_bin(self, other, '+');
|
|
1859
|
+
break;
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
/*
|
|
1864
|
+
* call-seq:
|
|
1865
|
+
* Complex128 - Numeric -> Complex128 | Complex
|
|
1866
|
+
*
|
|
1867
|
+
* 右オペランドを減算する.
|
|
1868
|
+
* 右オペランドがComplexクラスであればComplexクラスを,そのほかはComplex128クラスを返却値にそれぞれ演算する.
|
|
1869
|
+
*/
|
|
1870
|
+
static VALUE
|
|
1871
|
+
complex128_sub(VALUE self, VALUE other)
|
|
1872
|
+
{
|
|
1873
|
+
switch (convertion_num_types(other)) {
|
|
1874
|
+
case NUM_FIXNUM:
|
|
1875
|
+
case NUM_BIGNUM:
|
|
1876
|
+
return complex128_ope_integer(self, other, OPE_SUB);
|
|
1877
|
+
break;
|
|
1878
|
+
case NUM_RATIONAL:
|
|
1879
|
+
return complex128_ope_rational(self, other, OPE_SUB);
|
|
1880
|
+
break;
|
|
1881
|
+
case NUM_FLOAT:
|
|
1882
|
+
return complex128_ope_float(self, other, OPE_SUB);
|
|
1883
|
+
break;
|
|
1884
|
+
case NUM_COMPLEX:
|
|
1885
|
+
return complex128_ope_nucomp(self, other, OPE_SUB);
|
|
1886
|
+
break;
|
|
1887
|
+
case NUM_FLOAT128:
|
|
1888
|
+
return complex128_ope_float128(self, other, OPE_SUB);
|
|
1889
|
+
break;
|
|
1890
|
+
case NUM_COMPLEX128:
|
|
1891
|
+
return complex128_ope_complex128(self, other, OPE_SUB);
|
|
1892
|
+
break;
|
|
1893
|
+
case NUM_OTHERTYPE:
|
|
1894
|
+
default:
|
|
1895
|
+
return rb_num_coerce_bin(self, other, '-');
|
|
1896
|
+
break;
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
/*
|
|
1901
|
+
* call-seq:
|
|
1902
|
+
* Complex128 * Numeric -> Complex128 | Complex
|
|
1903
|
+
*
|
|
1904
|
+
* 右オペランドとの積を取る.
|
|
1905
|
+
* 右オペランドがComplexクラスであればComplexクラスを,そのほかはComplex128クラスを返却値にそれぞれ演算する.
|
|
1906
|
+
*/
|
|
1907
|
+
static VALUE
|
|
1908
|
+
complex128_mul(VALUE self, VALUE other)
|
|
1909
|
+
{
|
|
1910
|
+
switch (convertion_num_types(other)) {
|
|
1911
|
+
case NUM_FIXNUM:
|
|
1912
|
+
case NUM_BIGNUM:
|
|
1913
|
+
return complex128_ope_integer(self, other, OPE_MUL);
|
|
1914
|
+
break;
|
|
1915
|
+
case NUM_RATIONAL:
|
|
1916
|
+
return complex128_ope_rational(self, other, OPE_MUL);
|
|
1917
|
+
break;
|
|
1918
|
+
case NUM_FLOAT:
|
|
1919
|
+
return complex128_ope_float(self, other, OPE_MUL);
|
|
1920
|
+
break;
|
|
1921
|
+
case NUM_COMPLEX:
|
|
1922
|
+
return complex128_ope_nucomp(self, other, OPE_MUL);
|
|
1923
|
+
break;
|
|
1924
|
+
case NUM_FLOAT128:
|
|
1925
|
+
return complex128_ope_float128(self, other, OPE_MUL);
|
|
1926
|
+
break;
|
|
1927
|
+
case NUM_COMPLEX128:
|
|
1928
|
+
return complex128_ope_complex128(self, other, OPE_MUL);
|
|
1929
|
+
break;
|
|
1930
|
+
case NUM_OTHERTYPE:
|
|
1931
|
+
default:
|
|
1932
|
+
return rb_num_coerce_bin(self, other, '*');
|
|
1933
|
+
break;
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1937
|
+
/*
|
|
1938
|
+
* call-seq:
|
|
1939
|
+
* Complex128 / Numeric -> Complex128 | Complex
|
|
1940
|
+
*
|
|
1941
|
+
* 右オペランドとの商を取る.
|
|
1942
|
+
* 右オペランドがComplexクラスであればComplexクラスを,そのほかはComplex128クラスを返却値にそれぞれ演算する.
|
|
1943
|
+
*/
|
|
1944
|
+
static VALUE
|
|
1945
|
+
complex128_div(VALUE self, VALUE other)
|
|
1946
|
+
{
|
|
1947
|
+
switch (convertion_num_types(other)) {
|
|
1948
|
+
case NUM_FIXNUM:
|
|
1949
|
+
case NUM_BIGNUM:
|
|
1950
|
+
return complex128_ope_integer(self, other, OPE_DIV);
|
|
1951
|
+
break;
|
|
1952
|
+
case NUM_RATIONAL:
|
|
1953
|
+
return complex128_ope_rational(self, other, OPE_DIV);
|
|
1954
|
+
break;
|
|
1955
|
+
case NUM_FLOAT:
|
|
1956
|
+
return complex128_ope_float(self, other, OPE_DIV);
|
|
1957
|
+
break;
|
|
1958
|
+
case NUM_COMPLEX:
|
|
1959
|
+
return complex128_ope_nucomp(self, other, OPE_DIV);
|
|
1960
|
+
break;
|
|
1961
|
+
case NUM_FLOAT128:
|
|
1962
|
+
return complex128_ope_float128(self, other, OPE_DIV);
|
|
1963
|
+
break;
|
|
1964
|
+
case NUM_COMPLEX128:
|
|
1965
|
+
return complex128_ope_complex128(self, other, OPE_DIV);
|
|
1966
|
+
break;
|
|
1967
|
+
case NUM_OTHERTYPE:
|
|
1968
|
+
default:
|
|
1969
|
+
return rb_num_coerce_bin(self, other, '/');
|
|
1970
|
+
break;
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
/*
|
|
1975
|
+
* call-seq:
|
|
1976
|
+
* Complex128 % Numeric -> Complex128 | Complex
|
|
1977
|
+
*
|
|
1978
|
+
* 右オペランドと剰余計算を行う.
|
|
1979
|
+
* このメソッドは実装定義である.
|
|
1980
|
+
*/
|
|
1981
|
+
static VALUE
|
|
1982
|
+
complex128_mod(VALUE self, VALUE other)
|
|
1983
|
+
{
|
|
1984
|
+
switch (convertion_num_types(other)) {
|
|
1985
|
+
case NUM_FIXNUM:
|
|
1986
|
+
case NUM_BIGNUM:
|
|
1987
|
+
return complex128_ope_integer(self, other, OPE_MOD);
|
|
1988
|
+
break;
|
|
1989
|
+
case NUM_RATIONAL:
|
|
1990
|
+
return complex128_ope_rational(self, other, OPE_MOD);
|
|
1991
|
+
break;
|
|
1992
|
+
case NUM_FLOAT:
|
|
1993
|
+
return complex128_ope_float(self, other, OPE_MOD);
|
|
1994
|
+
break;
|
|
1995
|
+
case NUM_COMPLEX:
|
|
1996
|
+
return complex128_ope_nucomp(self, other, OPE_MOD);
|
|
1997
|
+
break;
|
|
1998
|
+
case NUM_FLOAT128:
|
|
1999
|
+
return complex128_ope_float128(self, other, OPE_MOD);
|
|
2000
|
+
break;
|
|
2001
|
+
case NUM_COMPLEX128:
|
|
2002
|
+
return complex128_ope_complex128(self, other, OPE_MOD);
|
|
2003
|
+
break;
|
|
2004
|
+
case NUM_OTHERTYPE:
|
|
2005
|
+
default:
|
|
2006
|
+
return rb_num_coerce_bin(self, other, '%');
|
|
2007
|
+
break;
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
/*
|
|
2012
|
+
* call-seq:
|
|
2013
|
+
* Complex128 ** Numeric -> Complex128 | Complex
|
|
2014
|
+
*
|
|
2015
|
+
* 右オペランドと累乗計算を行う.
|
|
2016
|
+
* 右オペランドがComplexクラスであればComplexクラスを,そのほかはComplex128クラスを返却値にそれぞれ演算する.
|
|
2017
|
+
*/
|
|
2018
|
+
static VALUE
|
|
2019
|
+
complex128_pow(VALUE self, VALUE other)
|
|
2020
|
+
{
|
|
2021
|
+
switch (convertion_num_types(other)) {
|
|
2022
|
+
case NUM_FIXNUM:
|
|
2023
|
+
case NUM_BIGNUM:
|
|
2024
|
+
return complex128_ope_integer(self, other, OPE_POW);
|
|
2025
|
+
break;
|
|
2026
|
+
case NUM_RATIONAL:
|
|
2027
|
+
return complex128_ope_rational(self, other, OPE_POW);
|
|
2028
|
+
break;
|
|
2029
|
+
case NUM_FLOAT:
|
|
2030
|
+
return complex128_ope_float(self, other, OPE_POW);
|
|
2031
|
+
break;
|
|
2032
|
+
case NUM_COMPLEX:
|
|
2033
|
+
return complex128_ope_nucomp(self, other, OPE_POW);
|
|
2034
|
+
break;
|
|
2035
|
+
case NUM_FLOAT128:
|
|
2036
|
+
return complex128_ope_float128(self, other, OPE_POW);
|
|
2037
|
+
break;
|
|
2038
|
+
case NUM_COMPLEX128:
|
|
2039
|
+
return complex128_ope_complex128(self, other, OPE_POW);
|
|
2040
|
+
break;
|
|
2041
|
+
case NUM_OTHERTYPE:
|
|
2042
|
+
default:
|
|
2043
|
+
return rb_num_coerce_bin(self, other, rb_intern("**"));
|
|
2044
|
+
break;
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
/*
|
|
2049
|
+
* call-seq:
|
|
2050
|
+
* Complex128 <=> Numeric -> -1 | 0 | 1 | nil
|
|
2051
|
+
*
|
|
2052
|
+
* オペランド同士の比較を行う.
|
|
2053
|
+
*/
|
|
2054
|
+
static VALUE
|
|
2055
|
+
complex128_cmp(VALUE self, VALUE other)
|
|
2056
|
+
{
|
|
2057
|
+
switch (convertion_num_types(other)) {
|
|
2058
|
+
case NUM_FIXNUM:
|
|
2059
|
+
case NUM_BIGNUM:
|
|
2060
|
+
return complex128_ope_integer(self, other, OPE_CMP);
|
|
2061
|
+
break;
|
|
2062
|
+
case NUM_RATIONAL:
|
|
2063
|
+
return complex128_ope_rational(self, other, OPE_CMP);
|
|
2064
|
+
break;
|
|
2065
|
+
case NUM_FLOAT:
|
|
2066
|
+
return complex128_ope_float(self, other, OPE_CMP);
|
|
2067
|
+
break;
|
|
2068
|
+
case NUM_COMPLEX:
|
|
2069
|
+
return complex128_ope_nucomp(self, other, OPE_CMP);
|
|
2070
|
+
break;
|
|
2071
|
+
case NUM_FLOAT128:
|
|
2072
|
+
return complex128_ope_float128(self, other, OPE_CMP);
|
|
2073
|
+
break;
|
|
2074
|
+
case NUM_COMPLEX128:
|
|
2075
|
+
return complex128_ope_complex128(self, other, OPE_CMP);
|
|
2076
|
+
break;
|
|
2077
|
+
case NUM_OTHERTYPE:
|
|
2078
|
+
default:
|
|
2079
|
+
return rb_num_coerce_cmp(self, other, rb_intern("<=>"));
|
|
2080
|
+
break;
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
/*
|
|
2085
|
+
* call-seq:
|
|
2086
|
+
* coerce(other) -> [other, self]
|
|
2087
|
+
*
|
|
2088
|
+
* +other+を+self+と等しくしたうえで[other, self]のペア配列にしてこれを返す.
|
|
2089
|
+
*/
|
|
2090
|
+
static VALUE
|
|
2091
|
+
complex128_coerce(int argc, VALUE *argv, VALUE self)
|
|
2092
|
+
{
|
|
2093
|
+
VALUE other;
|
|
2094
|
+
rb_scan_args(argc, argv, "10", &other);
|
|
2095
|
+
switch (convertion_num_types(other)) {
|
|
2096
|
+
case NUM_FIXNUM:
|
|
2097
|
+
case NUM_BIGNUM:
|
|
2098
|
+
return complex128_ope_integer(self, other, OPE_COERCE);
|
|
2099
|
+
break;
|
|
2100
|
+
case NUM_RATIONAL:
|
|
2101
|
+
return complex128_ope_rational(self, other, OPE_COERCE);
|
|
2102
|
+
break;
|
|
2103
|
+
case NUM_FLOAT:
|
|
2104
|
+
return complex128_ope_float(self, other, OPE_COERCE);
|
|
2105
|
+
break;
|
|
2106
|
+
case NUM_COMPLEX:
|
|
2107
|
+
return complex128_ope_nucomp(self, other, OPE_COERCE);
|
|
2108
|
+
break;
|
|
2109
|
+
case NUM_FLOAT128:
|
|
2110
|
+
return complex128_ope_float128(self, other, OPE_COERCE);
|
|
2111
|
+
break;
|
|
2112
|
+
case NUM_COMPLEX128:
|
|
2113
|
+
return complex128_ope_complex128(self, other, OPE_COERCE);
|
|
2114
|
+
break;
|
|
2115
|
+
case NUM_OTHERTYPE:
|
|
2116
|
+
default:
|
|
2117
|
+
return rb_call_super(argc, argv);
|
|
2118
|
+
break;
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
static VALUE
|
|
2123
|
+
complex128_polarize(VALUE rho, VALUE theta)
|
|
2124
|
+
{
|
|
2125
|
+
__float128 abs = get_real(rho),
|
|
2126
|
+
arg = get_real(theta);
|
|
2127
|
+
__complex128 expi = cexpiq(arg);
|
|
2128
|
+
return rb_complex128_cc128(abs * expi);
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
/*
|
|
2132
|
+
* call-seq:
|
|
2133
|
+
* Complex128.polar(rho, theta = 0) -> Complex128
|
|
2134
|
+
*
|
|
2135
|
+
* 極座標(絶対値と偏角)からComplex128を生成する.偏角はラジアンを与える.
|
|
2136
|
+
* 絶対値のみ与えた場合,偏角の値は0である.
|
|
2137
|
+
* 引数は四倍精度の浮動小数点を考慮する.
|
|
2138
|
+
* 考慮できない場合,暗黙の型変換を試みるが,できない場合はTypeErrorを引き起こす.
|
|
2139
|
+
* リテラルは浮動小数点のとき内部的には二倍->四倍と型変換する.そのため精度が落ちる場合がある.
|
|
2140
|
+
*
|
|
2141
|
+
* # 整数リテラルでの生成
|
|
2142
|
+
* Complex128.polar(3) # => (3.0+0.0i)
|
|
2143
|
+
* # 浮動小数点リテラルでの生成.ある程度は精度落ちしない
|
|
2144
|
+
* Complex.polar(3, 2.0) # => (-1.2484405096414273+2.727892280477045i)
|
|
2145
|
+
* Complex128.polar(3, 2.0) # => (-1.2484405096414271609927046885022+2.7278922804770450861880595977352i)
|
|
2146
|
+
* # 精度比較.ある環境の場合
|
|
2147
|
+
* Complex128.polar(3, Math::PI) # => (-2.9999999999999999999999999999999+3.67394039744205953167819779682499e-16i)
|
|
2148
|
+
* Complex128.polar(3, QuadMath::PI) # => (-3.0+2.60154303903713430743911320781301e-34i)
|
|
2149
|
+
*/
|
|
2150
|
+
static VALUE
|
|
2151
|
+
complex128_s_polar(int argc, VALUE *argv, VALUE self)
|
|
2152
|
+
{
|
|
2153
|
+
VALUE rho, theta;
|
|
2154
|
+
if (argc == 1)
|
|
2155
|
+
{
|
|
2156
|
+
theta = INT2FIX(0);
|
|
2157
|
+
rb_scan_args(argc, argv, "10", &rho);
|
|
2158
|
+
}
|
|
2159
|
+
else
|
|
2160
|
+
{
|
|
2161
|
+
rb_scan_args(argc, argv, "11", &rho, &theta);
|
|
2162
|
+
}
|
|
2163
|
+
return complex128_polarize(rho, theta);
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
static VALUE
|
|
2167
|
+
complex128_rectangularize(VALUE r, VALUE i)
|
|
2168
|
+
{
|
|
2169
|
+
__float128 real = get_real(r),
|
|
2170
|
+
imag = get_real(i);
|
|
2171
|
+
__complex128 z;
|
|
2172
|
+
__real__ z = real;
|
|
2173
|
+
__imag__ z = imag;
|
|
2174
|
+
return rb_complex128_cc128(z);
|
|
2175
|
+
}
|
|
2176
|
+
|
|
2177
|
+
/*
|
|
2178
|
+
* call-seq:
|
|
2179
|
+
* Complex128.rect(real, imag = 0) -> Complex128
|
|
2180
|
+
* Complex128.rectangular(real, imag = 0) -> Complex128
|
|
2181
|
+
*
|
|
2182
|
+
* 直交座標からComplex128を生成する.
|
|
2183
|
+
* 引数は四倍精度の浮動小数点を考慮する.
|
|
2184
|
+
* 考慮できない場合,暗黙の型変換を試みるが,できない場合はTypeErrorを引き起こす.
|
|
2185
|
+
*
|
|
2186
|
+
* Complex128.rect(3) # => (3.0+0.0i)
|
|
2187
|
+
*
|
|
2188
|
+
* Complex128.rect(3, QuadMath::PI) # => (3.0+3.1415926535897932384626433832795i)
|
|
2189
|
+
* # 二倍精度のπで生成.情報が足りないため途中から精度落ちする
|
|
2190
|
+
* Complex128.rect(3, Math::PI) # => (3.0+3.1415926535897931159979634685441i)
|
|
2191
|
+
*/
|
|
2192
|
+
static VALUE
|
|
2193
|
+
complex128_s_rect(int argc, VALUE *argv, VALUE self)
|
|
2194
|
+
{
|
|
2195
|
+
VALUE r, i;
|
|
2196
|
+
if (argc == 1)
|
|
2197
|
+
{
|
|
2198
|
+
i = INT2FIX(0);
|
|
2199
|
+
rb_scan_args(argc, argv, "10", &r);
|
|
2200
|
+
}
|
|
2201
|
+
else
|
|
2202
|
+
{
|
|
2203
|
+
rb_scan_args(argc, argv, "11", &r, &i);
|
|
2204
|
+
}
|
|
2205
|
+
return complex128_rectangularize(r, i);
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
|
|
2209
|
+
/*
|
|
2210
|
+
* call-seq:
|
|
2211
|
+
* strtoflt128(str) -> Float128
|
|
2212
|
+
* strtoflt128(str, sp: "") -> Float128
|
|
2213
|
+
*
|
|
2214
|
+
* This is a front end for the library function strtoflt128(). It takes a String as the first argument +str+ and converts it to Float128 type.
|
|
2215
|
+
* If the keyword argument +sp+ is given, the second argument +sp+ of strtoflt128() will be received as the out buffer.
|
|
2216
|
+
*
|
|
2217
|
+
* strtoflt128('inf') # => Infinity
|
|
2218
|
+
* strtoflt128('-1') # => -1.0
|
|
2219
|
+
* strtoflt128('0xdeadbeef') # => 3735928559.0
|
|
2220
|
+
* sp = '' # => ""
|
|
2221
|
+
* strtoflt128('0+1i', sp: sp) # => 0.0
|
|
2222
|
+
* sp # => "+1i"
|
|
2223
|
+
*/
|
|
2224
|
+
static VALUE
|
|
2225
|
+
f_strtoflt128(int argc, VALUE *argv, VALUE self)
|
|
2226
|
+
{
|
|
2227
|
+
static ID kwds[1];
|
|
2228
|
+
VALUE str, opts, sp;
|
|
2229
|
+
__float128 x;
|
|
2230
|
+
|
|
2231
|
+
if (!kwds[0]) kwds[0] = rb_intern_const("sp");
|
|
2232
|
+
|
|
2233
|
+
rb_scan_args(argc, argv, "10:", &str, &opts);
|
|
2234
|
+
|
|
2235
|
+
if (argc != 1)
|
|
2236
|
+
{
|
|
2237
|
+
char *next_pointer;
|
|
2238
|
+
|
|
2239
|
+
rb_get_kwargs(opts, kwds, 0, 1, &sp);
|
|
2240
|
+
|
|
2241
|
+
StringValue(sp);
|
|
2242
|
+
rb_str_resize(sp, 0);
|
|
2243
|
+
|
|
2244
|
+
x = strtoflt128(StringValuePtr(str), &next_pointer);
|
|
2245
|
+
|
|
2246
|
+
rb_str_cat_cstr(sp, next_pointer);
|
|
2247
|
+
}
|
|
2248
|
+
else
|
|
2249
|
+
x = strtoflt128(StringValuePtr(str), NULL);
|
|
2250
|
+
|
|
2251
|
+
return rb_float128_cf128(x);
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2254
|
+
static int
|
|
2255
|
+
xsnprintf(char *buf, size_t sz, char *format, int width, int prec, __float128 x)
|
|
2256
|
+
{
|
|
2257
|
+
int n;
|
|
2258
|
+
if (width == 0 && prec == 0)
|
|
2259
|
+
n = quadmath_snprintf(buf, sz, format, x);
|
|
2260
|
+
else if (width != 0 && prec == 0)
|
|
2261
|
+
n = quadmath_snprintf(buf, sz, format, width, x);
|
|
2262
|
+
else if (width == 0 && prec != 0)
|
|
2263
|
+
n = quadmath_snprintf(buf, sz, format, prec, x);
|
|
2264
|
+
else /* if (width != 0 && prec != 0) */
|
|
2265
|
+
n = quadmath_snprintf(buf, sz, format, width, prec, x);
|
|
2266
|
+
return n;
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
/*
|
|
2270
|
+
* call-seq:
|
|
2271
|
+
* quadmath_sprintf(format, *arg) -> String
|
|
2272
|
+
*
|
|
2273
|
+
* A front end that provides access to the quadmath_snprintf() library function.
|
|
2274
|
+
* Notice that the method name and argument count are slightly different from the library's.
|
|
2275
|
+
*
|
|
2276
|
+
* The format depends on the library functions.
|
|
2277
|
+
* The arguments of library functions are variable length and are determined by the compiler. Therefore, this front end handles this in the parser.
|
|
2278
|
+
* The parser is strict about formatting errors.
|
|
2279
|
+
*
|
|
2280
|
+
* The string is stored in an internal buffer and provided to the user level.
|
|
2281
|
+
* If the function throws an error because the internal buffer is insufficient, it will automatically allocate memory and pass it.
|
|
2282
|
+
*
|
|
2283
|
+
* quadmath_sprintf("%Qf", 2) # => "2.000000"
|
|
2284
|
+
* quadmath_sprintf("%Qf", 7/10r) # => "0.700000"
|
|
2285
|
+
* quadmath_sprintf("%.*Qf", Float128::DIG, 1/3r) # => "0.333333333333333333333333333333333"
|
|
2286
|
+
* quadmath_sprintf("%.*Qf", Float128::DIG, 1.0/3.0) # => "0.333333333333333314829616256247391"
|
|
2287
|
+
* quadmath_sprintf("%.*Qf", Float128::DIG, 1.to_f128 / 3) # => "0.333333333333333333333333333333333"
|
|
2288
|
+
* width = 46; prec = 20;
|
|
2289
|
+
* quadmath_sprintf("%+-#*.*Qe", width, prec, QuadMath.sqrt(2)) # => "+1.41421356237309504880e+00 "
|
|
2290
|
+
*/
|
|
2291
|
+
static VALUE
|
|
2292
|
+
f_quadmath_sprintf(int argc, VALUE *argv, VALUE self)
|
|
2293
|
+
{
|
|
2294
|
+
VALUE vformat, arg, apptd, retval;
|
|
2295
|
+
char *format;
|
|
2296
|
+
int fmt_stat = FMT_EMPTY, flags = 0, width = 0, prec = 0, float_type = FT_FLT;
|
|
2297
|
+
long arg_offset = 0;
|
|
2298
|
+
char notation = 'f';
|
|
2299
|
+
|
|
2300
|
+
rb_scan_args(argc, argv, "1*", &vformat, &arg);
|
|
2301
|
+
|
|
2302
|
+
format = StringValuePtr(vformat);
|
|
2303
|
+
retval = rb_str_new(0,0);
|
|
2304
|
+
|
|
2305
|
+
for (long i = 0; i < RSTRING_LEN(vformat); i++)
|
|
2306
|
+
{
|
|
2307
|
+
const char c = format[i];
|
|
2308
|
+
|
|
2309
|
+
if (fmt_stat == FMT_EMPTY && c != '%')
|
|
2310
|
+
continue;
|
|
2311
|
+
|
|
2312
|
+
switch (c) {
|
|
2313
|
+
case '%':
|
|
2314
|
+
if (fmt_stat == FMT_EMPTY)
|
|
2315
|
+
fmt_stat = FMT_DRCTV;
|
|
2316
|
+
else
|
|
2317
|
+
goto fmt_error;
|
|
2318
|
+
break;
|
|
2319
|
+
case '#':
|
|
2320
|
+
if (fmt_stat == FMT_DRCTV)
|
|
2321
|
+
flags |= FLAG_SHARP;
|
|
2322
|
+
else
|
|
2323
|
+
goto fmt_error;
|
|
2324
|
+
break;
|
|
2325
|
+
case ' ':
|
|
2326
|
+
if (fmt_stat == FMT_DRCTV)
|
|
2327
|
+
flags |= FLAG_SPACE;
|
|
2328
|
+
else
|
|
2329
|
+
goto fmt_error;
|
|
2330
|
+
break;
|
|
2331
|
+
case '+':
|
|
2332
|
+
if (fmt_stat == FMT_DRCTV)
|
|
2333
|
+
flags |= FLAG_PLUS;
|
|
2334
|
+
else
|
|
2335
|
+
goto fmt_error;
|
|
2336
|
+
break;
|
|
2337
|
+
case '-':
|
|
2338
|
+
if (fmt_stat == FMT_DRCTV)
|
|
2339
|
+
flags |= FLAG_MINUS;
|
|
2340
|
+
else
|
|
2341
|
+
goto fmt_error;
|
|
2342
|
+
break;
|
|
2343
|
+
case '0': case '1': case '2': case '3': case '4':
|
|
2344
|
+
case '5': case '6': case '7': case '8': case '9':
|
|
2345
|
+
if (fmt_stat == FMT_DRCTV)
|
|
2346
|
+
{
|
|
2347
|
+
if (c == '0')
|
|
2348
|
+
flags |= FLAG_ZERO;
|
|
2349
|
+
else
|
|
2350
|
+
fmt_stat = FMT_WIDTH;
|
|
2351
|
+
}
|
|
2352
|
+
else if (fmt_stat == FMT_POINT)
|
|
2353
|
+
{
|
|
2354
|
+
fmt_stat = FMT_PREC;
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
if (fmt_stat == FMT_WIDTH)
|
|
2358
|
+
{
|
|
2359
|
+
width = width * 10 + (c - '0');
|
|
2360
|
+
if (width < 0)
|
|
2361
|
+
goto biggest_width_error;
|
|
2362
|
+
}
|
|
2363
|
+
else if (fmt_stat == FMT_PREC)
|
|
2364
|
+
{
|
|
2365
|
+
prec = prec * 10 + (c - '0');
|
|
2366
|
+
if (prec < 0)
|
|
2367
|
+
goto biggest_prec_error;
|
|
2368
|
+
}
|
|
2369
|
+
else
|
|
2370
|
+
goto fmt_error;
|
|
2371
|
+
|
|
2372
|
+
break;
|
|
2373
|
+
case '*':
|
|
2374
|
+
if (fmt_stat == FMT_DRCTV)
|
|
2375
|
+
fmt_stat = FMT_WIDTH_SCALAR;
|
|
2376
|
+
else if (fmt_stat == FMT_POINT)
|
|
2377
|
+
fmt_stat = FMT_PREC_SCALAR;
|
|
2378
|
+
else
|
|
2379
|
+
goto fmt_error;
|
|
2380
|
+
|
|
2381
|
+
if (RARRAY_LEN(arg) <= arg_offset)
|
|
2382
|
+
goto too_few_arguments;
|
|
2383
|
+
else
|
|
2384
|
+
{
|
|
2385
|
+
VALUE item = rb_ary_entry(arg, arg_offset);
|
|
2386
|
+
long n;
|
|
2387
|
+
|
|
2388
|
+
if (!RB_TYPE_P(item, T_FIXNUM) ||
|
|
2389
|
+
!RB_TYPE_P(item, T_BIGNUM))
|
|
2390
|
+
item = rb_Integer(item);
|
|
2391
|
+
|
|
2392
|
+
n = NUM2LONG(item);
|
|
2393
|
+
|
|
2394
|
+
if (fmt_stat == FMT_WIDTH_SCALAR)
|
|
2395
|
+
{
|
|
2396
|
+
if (n < 0) goto biggest_width_error;
|
|
2397
|
+
width = (int)n;
|
|
2398
|
+
}
|
|
2399
|
+
else /* if (fmt_stat == FMT_PREC_SCALAR) */
|
|
2400
|
+
{
|
|
2401
|
+
if (n < 0) goto biggest_prec_error;
|
|
2402
|
+
prec = (int)n;
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2405
|
+
arg_offset++;
|
|
2406
|
+
}
|
|
2407
|
+
break;
|
|
2408
|
+
case '.':
|
|
2409
|
+
switch (fmt_stat) {
|
|
2410
|
+
case FMT_DRCTV:
|
|
2411
|
+
case FMT_WIDTH:
|
|
2412
|
+
case FMT_WIDTH_SCALAR:
|
|
2413
|
+
fmt_stat = FMT_POINT;
|
|
2414
|
+
break;
|
|
2415
|
+
default:
|
|
2416
|
+
goto fmt_error;
|
|
2417
|
+
}
|
|
2418
|
+
break;
|
|
2419
|
+
case 'l':
|
|
2420
|
+
if (fmt_stat == FMT_POINT || fmt_stat == FMT_SET_FT)
|
|
2421
|
+
goto fmt_error;
|
|
2422
|
+
|
|
2423
|
+
float_type = FT_DBL;
|
|
2424
|
+
fmt_stat = FMT_SET_FT;
|
|
2425
|
+
|
|
2426
|
+
break;
|
|
2427
|
+
case 'L':
|
|
2428
|
+
if (fmt_stat == FMT_POINT || fmt_stat == FMT_SET_FT)
|
|
2429
|
+
goto fmt_error;
|
|
2430
|
+
|
|
2431
|
+
float_type = FT_LDBL;
|
|
2432
|
+
fmt_stat = FMT_SET_FT;
|
|
2433
|
+
break;
|
|
2434
|
+
case 'Q':
|
|
2435
|
+
if (fmt_stat == FMT_POINT || fmt_stat == FMT_SET_FT)
|
|
2436
|
+
goto fmt_error;
|
|
2437
|
+
|
|
2438
|
+
float_type = FT_QUAD;
|
|
2439
|
+
fmt_stat = FMT_SET_FT;
|
|
2440
|
+
break;
|
|
2441
|
+
case 'a': case 'A':
|
|
2442
|
+
case 'e': case 'E':
|
|
2443
|
+
case 'f': case 'F':
|
|
2444
|
+
case 'g': case 'G':
|
|
2445
|
+
if (fmt_stat == FMT_POINT) goto fmt_error;
|
|
2446
|
+
|
|
2447
|
+
if (float_type == FT_QUAD)
|
|
2448
|
+
{
|
|
2449
|
+
if (RARRAY_LEN(arg) <= arg_offset)
|
|
2450
|
+
goto too_few_arguments;
|
|
2451
|
+
else
|
|
2452
|
+
{
|
|
2453
|
+
__float128 x = get_real(rb_ary_entry(arg, arg_offset));
|
|
2454
|
+
int n;
|
|
2455
|
+
char buf[BUF_SIZ];
|
|
2456
|
+
apptd = rb_usascii_str_new_cstr("%");
|
|
2457
|
+
notation = isupper(c) ? c + 0x20 : c;
|
|
2458
|
+
if (flags & FLAG_PLUS) rb_str_concat(apptd, CHR2FIX('+'));
|
|
2459
|
+
if (flags & FLAG_MINUS) rb_str_concat(apptd, CHR2FIX('-'));
|
|
2460
|
+
if (flags & FLAG_SHARP) rb_str_concat(apptd, CHR2FIX('#'));
|
|
2461
|
+
if (flags & FLAG_ZERO) rb_str_concat(apptd, CHR2FIX('0'));
|
|
2462
|
+
if (flags & FLAG_SPACE) rb_str_concat(apptd, CHR2FIX(' '));
|
|
2463
|
+
if (width != 0) rb_str_concat(apptd, CHR2FIX('*'));
|
|
2464
|
+
if (prec != 0) { rb_str_concat(apptd, CHR2FIX('.'));
|
|
2465
|
+
rb_str_concat(apptd, CHR2FIX('*')); }
|
|
2466
|
+
rb_str_concat(apptd, CHR2FIX('Q'));
|
|
2467
|
+
rb_str_concat(apptd, CHR2FIX(notation));
|
|
2468
|
+
|
|
2469
|
+
n = xsnprintf(buf, BUF_SIZ, StringValuePtr(apptd), width, prec, x);
|
|
2470
|
+
|
|
2471
|
+
if ((size_t)n < sizeof(buf))
|
|
2472
|
+
rb_str_cat_cstr(retval, buf);
|
|
2473
|
+
else
|
|
2474
|
+
{
|
|
2475
|
+
n = xsnprintf(NULL, 0, StringValuePtr(apptd), width, prec, x);
|
|
2476
|
+
if (n > -1)
|
|
2477
|
+
{
|
|
2478
|
+
char *str = ruby_xmalloc(n + 1);
|
|
2479
|
+
if (str)
|
|
2480
|
+
{
|
|
2481
|
+
xsnprintf(str, n + 1, StringValuePtr(apptd), width, prec, x);
|
|
2482
|
+
rb_str_cat_cstr(retval, str);
|
|
2483
|
+
}
|
|
2484
|
+
ruby_xfree(str);
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2489
|
+
goto return_value;
|
|
2490
|
+
break;
|
|
2491
|
+
default:
|
|
2492
|
+
goto fmt_error;
|
|
2493
|
+
break;
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
return_value:
|
|
2497
|
+
return retval;
|
|
2498
|
+
fmt_error:
|
|
2499
|
+
rb_raise(rb_eArgError, "format error");
|
|
2500
|
+
biggest_width_error:
|
|
2501
|
+
rb_raise(rb_eArgError, "biggest (or negative) width size");
|
|
2502
|
+
biggest_prec_error:
|
|
2503
|
+
rb_raise(rb_eArgError, "biggest (or negative) precision size");
|
|
2504
|
+
too_few_arguments:
|
|
2505
|
+
rb_raise(rb_eArgError, "too few arguments");
|
|
2506
|
+
}
|
|
2507
|
+
|
|
2508
|
+
static VALUE
|
|
2509
|
+
float128_rationalable(VALUE self)
|
|
2510
|
+
{
|
|
2511
|
+
VALUE string;
|
|
2512
|
+
__float128 x = rb_float128_value(self);
|
|
2513
|
+
|
|
2514
|
+
switch (fpclassify(x)) {
|
|
2515
|
+
case FP_NAN:
|
|
2516
|
+
|
|
2517
|
+
rb_raise(rb_eFloatDomainError, "NaN");
|
|
2518
|
+
break;
|
|
2519
|
+
case FP_INFINITE:
|
|
2520
|
+
if (signbitq(x))
|
|
2521
|
+
rb_raise(rb_eFloatDomainError, "-Infinity");
|
|
2522
|
+
else
|
|
2523
|
+
rb_raise(rb_eFloatDomainError, "Infinity");
|
|
2524
|
+
break;
|
|
2525
|
+
case FP_ZERO:
|
|
2526
|
+
self = rb_Rational1(INT2FIX(0));
|
|
2527
|
+
break;
|
|
2528
|
+
case FP_NORMAL:
|
|
2529
|
+
case FP_SUBNORMAL:
|
|
2530
|
+
default:
|
|
2531
|
+
string = float128_to_s(0, 0, self);
|
|
2532
|
+
self = rb_Rational1(string);
|
|
2533
|
+
break;
|
|
2534
|
+
}
|
|
2535
|
+
return self;
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2538
|
+
/*
|
|
2539
|
+
* call-seq:
|
|
2540
|
+
* to_r -> Rational
|
|
2541
|
+
*
|
|
2542
|
+
* Convert to Rational.
|
|
2543
|
+
*/
|
|
2544
|
+
static VALUE
|
|
2545
|
+
float128_to_r(VALUE self)
|
|
2546
|
+
{
|
|
2547
|
+
return float128_rationalable(self);
|
|
2548
|
+
}
|
|
2549
|
+
|
|
2550
|
+
/*
|
|
2551
|
+
* call-seq:
|
|
2552
|
+
* to_r -> Rational
|
|
2553
|
+
*
|
|
2554
|
+
* Convert to Rational.
|
|
2555
|
+
*/
|
|
2556
|
+
static VALUE
|
|
2557
|
+
complex128_to_r(VALUE self)
|
|
2558
|
+
{
|
|
2559
|
+
__complex128 z = rb_complex128_value(self);;
|
|
2560
|
+
|
|
2561
|
+
if (fpclassify(cimagq(z)) != FP_ZERO)
|
|
2562
|
+
rb_raise(rb_eTypeError,
|
|
2563
|
+
"can't convert %"PRIsVALUE" into Rational", self);
|
|
2564
|
+
|
|
2565
|
+
return float128_rationalable(rb_float128_cf128(crealq(z)));
|
|
2566
|
+
}
|
|
2567
|
+
|
|
2568
|
+
|
|
2569
|
+
|
|
2570
|
+
void
|
|
2571
|
+
InitVM_Numerable(void)
|
|
2572
|
+
{
|
|
2573
|
+
/* Numerical Type Conversions */
|
|
2574
|
+
rb_define_method(rb_cString, "to_f128", string_to_f128, 0);
|
|
2575
|
+
rb_define_method(rb_cString, "to_c128", string_to_c128, 0);
|
|
2576
|
+
|
|
2577
|
+
rb_define_method(rb_cNumeric, "to_f128", numeric_to_f128, 0);
|
|
2578
|
+
rb_define_method(rb_cNumeric, "to_c128", numeric_to_c128, 0);
|
|
2579
|
+
|
|
2580
|
+
rb_undef_method(rb_cNumeric, "to_f128");
|
|
2581
|
+
rb_undef_method(rb_cNumeric, "to_c128");
|
|
2582
|
+
|
|
2583
|
+
rb_define_method(rb_cInteger, "to_f128", integer_to_f128, 0);
|
|
2584
|
+
rb_define_method(rb_cInteger, "to_c128", integer_to_c128, 0);
|
|
2585
|
+
|
|
2586
|
+
rb_define_method(rb_cRational, "to_f128", rational_to_f128, 0);
|
|
2587
|
+
rb_define_method(rb_cRational, "to_c128", rational_to_c128, 0);
|
|
2588
|
+
|
|
2589
|
+
rb_define_method(rb_cFloat, "to_f128", float_to_f128, 0);
|
|
2590
|
+
rb_define_method(rb_cFloat, "to_c128", float_to_c128, 0);
|
|
2591
|
+
|
|
2592
|
+
rb_define_method(rb_cComplex, "to_f128", nucomp_to_f128, 0);
|
|
2593
|
+
rb_define_method(rb_cComplex, "to_c128", nucomp_to_c128, 0);
|
|
2594
|
+
|
|
2595
|
+
/* Global function */
|
|
2596
|
+
rb_define_global_function("Float128", f_Float128, -1);
|
|
2597
|
+
rb_define_global_function("Complex128", f_Complex128, -1);
|
|
2598
|
+
rb_define_global_function("strtoflt128", f_strtoflt128, -1);
|
|
2599
|
+
rb_define_global_function("quadmath_sprintf", f_quadmath_sprintf, -1);
|
|
2600
|
+
|
|
2601
|
+
/* Singleton Methods */
|
|
2602
|
+
rb_define_singleton_method(rb_cFloat128, "fma", float128_s_fma, -1);
|
|
2603
|
+
rb_define_singleton_method(rb_cFloat128, "sincos", float128_s_sincos, -1);
|
|
2604
|
+
rb_define_singleton_method(rb_cFloat128, "fmin", float128_s_fmin, -1);
|
|
2605
|
+
rb_define_singleton_method(rb_cFloat128, "fmax", float128_s_fmax, -1);
|
|
2606
|
+
rb_define_singleton_method(rb_cFloat128, "ldexp", float128_s_ldexp, 2);
|
|
2607
|
+
rb_define_singleton_method(rb_cFloat128, "scalb", float128_s_scalb, 2);
|
|
2608
|
+
rb_define_singleton_method(rb_cFloat128, "scalbn", float128_s_scalb, 2);
|
|
2609
|
+
rb_define_singleton_method(rb_cComplex128, "polar", complex128_s_polar, -1);
|
|
2610
|
+
rb_define_singleton_method(rb_cComplex128, "rect", complex128_s_rect, -1);
|
|
2611
|
+
rb_define_singleton_method(rb_cComplex128, "rectangular", complex128_s_rect, -1);
|
|
2612
|
+
|
|
2613
|
+
/* Operators & Evals */
|
|
2614
|
+
rb_define_method(rb_cFloat128, "polar", float128_polar, 0);
|
|
2615
|
+
rb_define_method(rb_cFloat128, "abs", float128_abs, 0);
|
|
2616
|
+
rb_define_alias(rb_cFloat128, "magnitude", "abs");
|
|
2617
|
+
rb_define_method(rb_cFloat128, "abs2", float128_abs2, 0);
|
|
2618
|
+
rb_define_method(rb_cFloat128, "arg", float128_arg, 0);
|
|
2619
|
+
rb_define_alias(rb_cFloat128, "angle", "arg");
|
|
2620
|
+
rb_define_alias(rb_cFloat128, "phase", "arg");
|
|
2621
|
+
|
|
2622
|
+
rb_define_method(rb_cFloat128, "+", float128_add, 1);
|
|
2623
|
+
rb_define_method(rb_cFloat128, "-", float128_sub, 1);
|
|
2624
|
+
rb_define_method(rb_cFloat128, "*", float128_mul, 1);
|
|
2625
|
+
rb_define_method(rb_cFloat128, "/", float128_div, 1);
|
|
2626
|
+
rb_define_method(rb_cFloat128, "%", float128_mod, 1);
|
|
2627
|
+
rb_define_method(rb_cFloat128, "modulo", float128_mod, 1);
|
|
2628
|
+
rb_define_method(rb_cFloat128, "**", float128_pow, 1);
|
|
2629
|
+
rb_define_method(rb_cFloat128, "<=>", float128_cmp, 1);
|
|
2630
|
+
rb_define_method(rb_cFloat128, "coerce", float128_coerce, -1);
|
|
2631
|
+
|
|
2632
|
+
rb_define_method(rb_cComplex128, "polar", complex128_polar, 0);
|
|
2633
|
+
rb_define_method(rb_cComplex128, "abs", complex128_abs, 0);
|
|
2634
|
+
rb_define_alias(rb_cComplex128, "magnitude", "abs");
|
|
2635
|
+
rb_define_method(rb_cComplex128, "abs2", complex128_abs2, 0);
|
|
2636
|
+
rb_define_method(rb_cComplex128, "arg", complex128_arg, 0);
|
|
2637
|
+
rb_define_alias(rb_cComplex128, "angle", "arg");
|
|
2638
|
+
rb_define_alias(rb_cComplex128, "phase", "arg");
|
|
2639
|
+
rb_define_method(rb_cComplex128, "conj", complex128_conj, 0);
|
|
2640
|
+
|
|
2641
|
+
rb_define_method(rb_cComplex128, "+", complex128_add, 1);
|
|
2642
|
+
rb_define_method(rb_cComplex128, "-", complex128_sub, 1);
|
|
2643
|
+
rb_define_method(rb_cComplex128, "*", complex128_mul, 1);
|
|
2644
|
+
rb_define_method(rb_cComplex128, "/", complex128_div, 1);
|
|
2645
|
+
rb_define_method(rb_cComplex128, "%", complex128_mod, 1);
|
|
2646
|
+
rb_define_method(rb_cComplex128, "modulo", complex128_mod, 1);
|
|
2647
|
+
rb_define_method(rb_cComplex128, "**", complex128_pow, 1);
|
|
2648
|
+
rb_define_method(rb_cComplex128, "<=>", complex128_cmp, 1);
|
|
2649
|
+
rb_define_method(rb_cComplex128, "coerce", complex128_coerce, -1);
|
|
2650
|
+
|
|
2651
|
+
rb_undef_method(rb_cComplex128, "%");
|
|
2652
|
+
rb_undef_method(rb_cComplex128, "modulo");
|
|
2653
|
+
|
|
2654
|
+
/* Rational */
|
|
2655
|
+
rb_define_method(rb_cFloat128, "to_r", float128_to_r, 0);
|
|
2656
|
+
rb_define_method(rb_cComplex128, "to_r", complex128_to_r, 0);
|
|
2657
|
+
}
|