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.
@@ -0,0 +1,494 @@
1
+ /*******************************************************************************
2
+ complex128.c -- Complex128 Class
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
+ char ool_quad2str(__float128 x, char format, int *exp, int *sign, char **buf);
12
+
13
+ struct C128 { __complex128 value; } ;
14
+
15
+ static void
16
+ free_complex128(void *v)
17
+ {
18
+ if (v != NULL)
19
+ {
20
+ xfree(v);
21
+ }
22
+ }
23
+
24
+ static size_t
25
+ memsize_complex128(const void *_)
26
+ {
27
+ return sizeof(struct C128);
28
+ }
29
+
30
+ static const rb_data_type_t complex128_data_type = {
31
+ "complex128",
32
+ {0, free_complex128, memsize_complex128,},
33
+ 0, 0,
34
+ RUBY_TYPED_FREE_IMMEDIATELY,
35
+ };
36
+
37
+ static VALUE
38
+ complex128_allocate(__complex128 x)
39
+ {
40
+ struct C128 *ptr = ruby_xcalloc(1, sizeof(struct C128));
41
+ VALUE obj;
42
+ ptr->value = x;
43
+ obj = TypedData_Wrap_Struct(rb_cComplex128, &complex128_data_type, ptr);
44
+ RB_OBJ_FREEZE(obj);
45
+ return obj;
46
+ }
47
+
48
+ __complex128
49
+ GetC128(VALUE self)
50
+ {
51
+ struct C128 *c128;
52
+
53
+ TypedData_Get_Struct(self, struct C128, &complex128_data_type, c128);
54
+
55
+ return c128->value;
56
+ }
57
+
58
+ /*
59
+ * call-seq:
60
+ * hash -> Integer
61
+ *
62
+ * +self+のHash値を返す.
63
+ *
64
+ */
65
+ static VALUE
66
+ complex128_hash(VALUE self)
67
+ {
68
+ struct C128 *c128;;
69
+ st_index_t hash;
70
+
71
+ TypedData_Get_Struct(self, struct C128, &complex128_data_type, c128);
72
+
73
+ hash = rb_memhash(c128, sizeof(struct C128));
74
+
75
+ return ST2FIX(hash);
76
+ }
77
+
78
+ /*
79
+ * call-seq:
80
+ * eql?(other) -> bool
81
+ *
82
+ * +self+と+other+が等しければ真を返す.
83
+ */
84
+ static VALUE
85
+ complex128_eql_p(VALUE self, VALUE other)
86
+ {
87
+ __complex128 left_c128, right_c128;
88
+
89
+ if (CLASS_OF(other) != rb_cComplex128)
90
+ return Qfalse;
91
+
92
+ left_c128 = GetC128(self);
93
+ right_c128 = GetC128(other);
94
+
95
+ return left_c128 == right_c128 ? Qtrue : Qfalse;
96
+ }
97
+
98
+ /*
99
+ * call-seq:
100
+ * infinite? -> nil | 1
101
+ *
102
+ * +self+が無限複素量であるかを確認する.実部・虚部がともに有限であればnilを,そうでなければ1を返す.
103
+
104
+ */
105
+ static VALUE
106
+ complex128_infinite_p(VALUE self)
107
+ {
108
+ __complex128 c128 = GetC128(self);
109
+
110
+ return (isinfq(crealq(c128)) || isinfq(cimagq(c128))) ?
111
+ INT2FIX(1) : Qnil;
112
+ }
113
+
114
+ /*
115
+ * call-seq:
116
+ * finite? -> bool
117
+ *
118
+ * +self+の実部・虚部がともに有限であればtrueを,そうでなければfalseを返す.
119
+
120
+ */
121
+ static VALUE
122
+ complex128_finite_p(VALUE self)
123
+ {
124
+ __complex128 c128 = GetC128(self);
125
+ __float128 real, imag;
126
+
127
+ real = crealq(c128); imag = cimagq(c128);
128
+
129
+ return (finiteq(real) && finiteq(imag)) ? Qtrue : Qfalse;
130
+ }
131
+
132
+ static char
133
+ member_format(__float128 x, VALUE s)
134
+ {
135
+ char* str;
136
+ int exp, sign;
137
+ char format = ool_quad2str(fabsq(x), 'g', &exp, &sign, &str);
138
+
139
+ switch (format) {
140
+ case '0':
141
+ rb_raise(rb_eRuntimeError, "error occured in ool_quad2str()");
142
+ break;
143
+ case '1':
144
+ rb_str_concat(s, rb_sprintf("%s", str));
145
+ break;
146
+ case 'e':
147
+ rb_str_concat(s, rb_sprintf("%se%+d", str, exp));
148
+ break;
149
+ case 'f':
150
+ rb_str_concat(s, rb_sprintf("%s", str));
151
+ break;
152
+ default:
153
+ rb_raise(rb_eRuntimeError, "format error");
154
+ break;
155
+ }
156
+ return format;
157
+ }
158
+
159
+ static VALUE
160
+ f_format(VALUE self)
161
+ {
162
+ VALUE retval = rb_str_new(0,0);
163
+ __complex128 c128 = GetC128(self);
164
+ char format;
165
+ __float128 memb;
166
+
167
+ memb = crealq(c128);
168
+ if (signbitq(memb)) rb_str_cat2(retval, "-");
169
+ member_format(memb, retval);
170
+
171
+ memb = cimagq(c128);
172
+ rb_str_cat2(retval, !signbitq(memb) ? "+" : "-");
173
+ format = member_format(memb, retval);
174
+ if (format == '1') rb_str_cat2(retval, "*");
175
+ rb_str_cat2(retval, "i");
176
+
177
+ return retval;
178
+ }
179
+
180
+ /*
181
+ * call-seq:
182
+ * to_s -> String
183
+ *
184
+ * +self+をStringに変換する.
185
+ */
186
+ static VALUE
187
+ complex128_to_s(VALUE self)
188
+ {
189
+ return f_format(self);
190
+ }
191
+
192
+ /*
193
+ * call-seq:
194
+ * inspect -> String
195
+ *
196
+ * +self+を(Re+Im)の形で見やすくする.
197
+ */
198
+ static VALUE
199
+ complex128_inspect(VALUE self)
200
+ {
201
+ VALUE s;
202
+
203
+ s = rb_usascii_str_new2("(");
204
+ rb_str_concat(s, f_format(self));
205
+ rb_str_cat2(s, ")");
206
+
207
+ return s;
208
+ }
209
+
210
+
211
+ /*
212
+ * call-seq:
213
+ * to_i -> Integer
214
+ *
215
+ * +self+を整数にして返す.
216
+ * 虚部がゼロでない(すなわち虚数が現れている)ならRangeErrorが,
217
+ * 実部が非数か無限ならFloatDomainErrorが発生する.
218
+ */
219
+ static VALUE
220
+ complex128_to_i(VALUE self)
221
+ {
222
+ __complex128 c128 = GetC128(self);
223
+
224
+ if (cimagq(c128) == 0)
225
+ {
226
+ __float128 real = crealq(c128);
227
+ if (FIXABLE(real))
228
+ return LONG2FIX((long)real);
229
+ else
230
+ {
231
+ VALUE f128 = rb_float128_cf128(real);
232
+ return rb_funcall(f128, rb_intern("to_i"), 0);
233
+ }
234
+ }
235
+ else
236
+ rb_raise(rb_eRangeError,
237
+ "can't convert %"PRIsVALUE" into %s",
238
+ rb_String(self), rb_class2name(rb_cInteger));
239
+ }
240
+
241
+ /*
242
+ * call-seq:
243
+ * to_f -> Float
244
+ *
245
+ * +self+をFloat型にして返す.
246
+ * 内部的にはいったん__float128型を取り出してdouble型にキャストしている.
247
+ * 虚部がゼロでない(すなわち虚数が現れている)ならRangeErrorが発生する.
248
+ */
249
+ static VALUE
250
+ complex128_to_f(VALUE self)
251
+ {
252
+ __complex128 c128 = GetC128(self);
253
+
254
+ if (cimagq(c128) == 0)
255
+ return DBL2NUM((double)crealq(c128));
256
+ else
257
+ rb_raise(rb_eRangeError,
258
+ "can't convert %"PRIsVALUE" into %s",
259
+ rb_String(self), rb_class2name(rb_cFloat));
260
+ }
261
+
262
+ /*
263
+ * call-seq:
264
+ * to_f128 -> Float128
265
+ *
266
+ * +self+をFloat128型にして返す.
267
+ * 虚部がゼロでない(すなわち虚数が現れている)ならRangeErrorが発生する.
268
+ */
269
+ static VALUE
270
+ complex128_to_f128(VALUE self)
271
+ {
272
+ __complex128 c128 = GetC128(self);
273
+
274
+ if (cimagq(c128) == 0)
275
+ return rb_float128_cf128(crealq(c128));
276
+ else
277
+ rb_raise(rb_eRangeError,
278
+ "can't convert %"PRIsVALUE" into %s",
279
+ rb_String(self), rb_class2name(rb_cFloat128));
280
+ }
281
+
282
+ /*
283
+ * call-seq:
284
+ * to_c -> Complex
285
+ *
286
+ * +self+をComplex型にして返す.
287
+ * 実部・虚部は取り出され,Complex型のメンバ変数としてフックされる.
288
+ */
289
+ static VALUE
290
+ complex128_to_c(VALUE self)
291
+ {
292
+ __complex128 c128 = GetC128(self);
293
+
294
+ return rb_Complex(
295
+ rb_float128_cf128(crealq(c128)),
296
+ rb_float128_cf128(cimagq(c128)));
297
+ }
298
+
299
+ /*
300
+ * call-seq:
301
+ * to_c128 -> Complex128
302
+ *
303
+ * 常に+self+を返す.
304
+ */
305
+ static VALUE
306
+ complex128_to_c128(VALUE self)
307
+ {
308
+ return self;
309
+ }
310
+
311
+ /*
312
+ * call-seq:
313
+ * real -> Float128
314
+ *
315
+ * +self+の実部を返す.型はFloat128である.
316
+ */
317
+ static VALUE
318
+ complex128_real(VALUE self)
319
+ {
320
+ __complex128 c128 = GetC128(self);
321
+
322
+ return rb_float128_cf128(crealq(c128));
323
+ }
324
+
325
+ /*
326
+ * call-seq:
327
+ * imag -> Float128
328
+ * imaginary -> Float128
329
+ *
330
+ * +self+の虚部を返す.型はFloat128である.
331
+ */
332
+ static VALUE
333
+ complex128_imag(VALUE self)
334
+ {
335
+ __complex128 c128 = GetC128(self);
336
+
337
+ return rb_float128_cf128(cimagq(c128));
338
+ }
339
+
340
+ /*
341
+ * call-seq:
342
+ * rect -> [Float128, Float128]
343
+ * rectangular -> [Float128, Float128]
344
+ *
345
+ * 実部と虚部を配列にして返す.
346
+ * 見た目はComplex型と変わりないが,成分はFloat128型のみなのが異なる.
347
+ *
348
+ * Complex128(3).rect # => [3.0, 0.0]
349
+ * Complex128(3.5).rect # => [3.5, 0.0]
350
+ * Complex128(3, 2).rect # => [3.0, 2.0]
351
+ * Complex128(1, 1).rect.all?(Float128) # => true
352
+ */
353
+ static VALUE
354
+ complex128_rect(VALUE self)
355
+ {
356
+ __complex128 c128 = GetC128(self);
357
+
358
+ return rb_assoc_new(
359
+ rb_float128_cf128(crealq(c128)),
360
+ rb_float128_cf128(cimagq(c128)));
361
+ }
362
+
363
+ /*
364
+ * call-seq:
365
+ * real? -> false
366
+ *
367
+ * 常にfalseを返す.
368
+ */
369
+ static VALUE
370
+ complex128_real_p(VALUE self)
371
+ {
372
+ return Qfalse;
373
+ }
374
+
375
+
376
+ #if 0
377
+ static VALUE
378
+ complex128_initialize_copy(VALUE self, VALUE other)
379
+ {
380
+ struct C128 *pv = rb_check_typeddata(self, &complex128_data_type);
381
+ struct C128 *x = rb_check_typeddata(other, &complex128_data_type);
382
+
383
+ if (self != other)
384
+ {
385
+ pv->value = x->value;
386
+ }
387
+ return self;
388
+ }
389
+ #endif
390
+
391
+ /*
392
+ * call-seq:
393
+ * to_c64 -> Complex
394
+ *
395
+ * +self+を二倍精度に精度引き下げしてこれをComplexに変換し返す.
396
+ *
397
+ * QuadMath.asin(1.1r).to_c64 # => (1.5707963267948966+0.4435682543851152i)
398
+ */
399
+ static VALUE
400
+ complex128_to_c64(VALUE self)
401
+ {
402
+ __complex128 c128 = GetC128(self);
403
+ return rb_dbl_complex_new((double)crealq(c128), (double)cimagq(c128));
404
+ }
405
+
406
+ static VALUE
407
+ f128_to_f64(VALUE obj)
408
+ {
409
+ __float128 elem = GetF128(obj);
410
+ return DBL2NUM((double)elem);
411
+ }
412
+
413
+ /*
414
+ * call-seq:
415
+ * to_c64 -> Complex
416
+ *
417
+ * +self+の成分が四倍精度の場合,二倍精度に精度引き下げして返す.
418
+ *
419
+ * z = Complex(3.to_f128) # => (3.0+0i)
420
+ * z.real.class # => Float128
421
+ * z.to_c64.real.class # => Float
422
+
423
+ */
424
+ static VALUE
425
+ nucomp_to_c64(VALUE self)
426
+ {
427
+ VALUE real = rb_complex_real(self);
428
+ VALUE imag = rb_complex_imag(self);
429
+
430
+ if (CLASS_OF(real) == rb_cFloat128)
431
+ real = f128_to_f64(real);
432
+ if (CLASS_OF(imag) == rb_cFloat128)
433
+ imag = f128_to_f64(imag);
434
+
435
+ return rb_Complex(real, imag);
436
+ }
437
+
438
+
439
+ void
440
+ InitVM_Complex128(void)
441
+ {
442
+ /* Class methods */
443
+ rb_undef_alloc_func(rb_cComplex128);
444
+ rb_undef_method(CLASS_OF(rb_cComplex128), "new");
445
+
446
+ /* Object methods */
447
+ rb_define_method(rb_cComplex128, "hash", complex128_hash, 0);
448
+ rb_define_method(rb_cComplex128, "eql?", complex128_eql_p, 1);
449
+
450
+ /* The unique methods */
451
+ rb_define_method(rb_cComplex128, "real?", complex128_real_p, 0);
452
+ rb_define_method(rb_cComplex128, "real", complex128_real, 0);
453
+ rb_define_method(rb_cComplex128, "imag", complex128_imag, 0);
454
+ rb_define_alias(rb_cComplex128, "imaginary", "imag");
455
+ rb_define_method(rb_cComplex128, "rect", complex128_rect, 0);
456
+ rb_define_alias(rb_cComplex128, "rectangular", "rect");
457
+ rb_undef_method(rb_cComplex128, "i");
458
+ rb_define_method(rb_cComplex128, "infinite?", complex128_infinite_p, 0);
459
+ rb_define_method(rb_cComplex128, "finite?", complex128_finite_p, 0);
460
+
461
+ /* Type convertion methods */
462
+ rb_define_method(rb_cComplex128, "to_s", complex128_to_s, 0);
463
+ rb_define_method(rb_cComplex128, "inspect", complex128_inspect, 0);
464
+
465
+ rb_define_method(rb_cComplex128, "to_f", complex128_to_f, 0);
466
+ rb_define_method(rb_cComplex128, "to_f128", complex128_to_f128, 0);
467
+
468
+ rb_define_method(rb_cComplex128, "to_i", complex128_to_i, 0);
469
+ rb_define_method(rb_cComplex128, "to_int", complex128_to_i, 0);
470
+
471
+ rb_define_method(rb_cComplex128, "to_c", complex128_to_c, 0);
472
+ rb_define_method(rb_cComplex128, "to_c128", complex128_to_c128, 0);
473
+
474
+ rb_define_method(rb_cComplex128, "to_c64", complex128_to_c64, 0);
475
+ rb_define_method(rb_cComplex, "to_c64", nucomp_to_c64, 0);
476
+
477
+ /* Constants */
478
+ rb_define_const(rb_cComplex128, "I", rb_complex128_cc128(0+1i));
479
+ }
480
+
481
+ VALUE
482
+ rb_complex128_cc128(__complex128 x)
483
+ {
484
+ VALUE obj = complex128_allocate(x);
485
+ return obj;
486
+ }
487
+
488
+ __complex128
489
+ rb_complex128_value(VALUE x)
490
+ {
491
+ struct C128 *c128 = rb_check_typeddata(x, &complex128_data_type);
492
+
493
+ return c128->value;
494
+ }
@@ -0,0 +1,15 @@
1
+ require 'mkmf'
2
+
3
+ if have_header('quadmath.h')
4
+ have_func('rb_opts_exception_p', 'ruby.h')
5
+ have_func('cerfq', 'quadmath.h')
6
+ have_func('cerfcq', 'quadmath.h')
7
+ have_func('clgammaq', 'quadmath.h')
8
+ have_func('ctgammaq', 'quadmath.h')
9
+ have_func('cl2norm2q', 'quadmath.h')
10
+
11
+ $libs << " -lquadmath"
12
+ create_makefile('quadmath/quadmath')
13
+ else
14
+ $stderr.puts "quadmath not found"
15
+ end