gmp 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,584 @@
1
+ #include <gmpz.h>
2
+ #include <gmpq.h>
3
+ #include <gmpf.h>
4
+
5
+ /*
6
+ * Document-class: GMP::F
7
+ *
8
+ * GMP Multiple Precision floating point numbers.
9
+ *
10
+ * Instances of this class can store variables of the type mpf_t. This class
11
+ * also contains many methods that act as the functions for mpf_t variables,
12
+ * as well as a few methods that attempt to make this library more Ruby-ish.
13
+ */
14
+
15
+ /**********************************************************************
16
+ * Macros *
17
+ **********************************************************************/
18
+
19
+ #define DEFUN_FLOAT2FLOAT(fname,mpf_fname) \
20
+ static VALUE r_gmpf_##fname(VALUE self) \
21
+ { \
22
+ MP_FLOAT *self_val, *res_val; \
23
+ VALUE res; \
24
+ mpf_get_struct(self, self_val); \
25
+ mpf_make_struct_init(res, res_val, mpf_get_prec(self_val)); \
26
+ mpf_fname(res_val, self_val); \
27
+ return res; \
28
+ } \
29
+ \
30
+ static VALUE r_gmpf_##fname##_self(VALUE self) \
31
+ { \
32
+ MP_FLOAT *self_val; \
33
+ mpf_get_struct(self, self_val); \
34
+ mpf_fname(self_val, self_val); \
35
+ return Qnil; \
36
+ }
37
+
38
+ #define DEFUN_FLOAT_CMP(name,CMP_OP) \
39
+ static VALUE r_gmpf_cmp_##name(VALUE self, VALUE arg) \
40
+ { \
41
+ MP_FLOAT *self_val; \
42
+ mpf_get_struct(self,self_val); \
43
+ return (mpf_cmp_value(self_val, arg) CMP_OP 0)?Qtrue:Qfalse; \
44
+ }
45
+
46
+
47
+ /**********************************************************************
48
+ * Initializing, Assigning Floats *
49
+ **********************************************************************/
50
+
51
+ /*
52
+ * call-seq:
53
+ * GMP::R.new(arg)
54
+ *
55
+ * Creates a new GMP::R float, with arg as its value, converting where
56
+ * necessary.
57
+ */
58
+ VALUE r_gmpfsg_new(int argc, VALUE *argv, VALUE klass)
59
+ {
60
+ MP_FLOAT *res_val;
61
+ VALUE res;
62
+
63
+ (void)klass;
64
+
65
+ if (argc > 2)
66
+ rb_raise(rb_eArgError, "wrong # of arguments(%d for 0, 1 or 2)", argc);
67
+
68
+ mpf_make_struct (res, res_val);
69
+ rb_obj_call_init(res, argc, argv);
70
+
71
+ return res;
72
+ }
73
+
74
+ VALUE r_gmpf_initialize(int argc, VALUE *argv, VALUE self)
75
+ {
76
+ MP_FLOAT *self_val, *arg_val_f;
77
+ unsigned long prec = 0;
78
+ VALUE arg;
79
+
80
+ mpf_get_struct (self, self_val);
81
+
82
+ if (argc==0) {
83
+ mpf_init(self_val);
84
+ mpf_set_si(self_val, 0);
85
+ return Qnil;
86
+ }
87
+
88
+ arg = argv[0];
89
+
90
+ if (argc == 2) {
91
+ if (FIXNUM_P(argv[1])) {
92
+ if (FIX2INT(argv[1]) >= 0)
93
+ prec = FIX2INT(argv[1]);
94
+ else
95
+ rb_raise(rb_eRangeError, "prec must be non-negative");
96
+ } else {
97
+ rb_raise(rb_eTypeError, "prec must be FixNum");
98
+ }
99
+ } else if (GMPF_P(arg)) {
100
+ mpf_get_struct (arg, arg_val_f);
101
+ prec = mpf_get_prec (arg_val_f);
102
+ }
103
+ if (prec == 0)
104
+ mpf_init (self_val);
105
+ else
106
+ mpf_init2 (self_val, prec);
107
+
108
+ if (GMPF_P(arg)) {
109
+ mpf_get_struct (arg, arg_val_f);
110
+ mpf_set(self_val, arg_val_f);
111
+ } else {
112
+ mpf_set_value(self_val, arg);
113
+ }
114
+
115
+ return Qnil;
116
+ }
117
+
118
+ /*
119
+ * call-seq:
120
+ * GMP::F(arg)
121
+ *
122
+ * A convenience method for +GMP::F.new(arg)+.
123
+ */
124
+ VALUE r_gmpmod_f(int argc, VALUE *argv, VALUE module)
125
+ {
126
+ (void)module;
127
+ return r_gmpfsg_new(argc, argv, cGMP_F);
128
+ }
129
+
130
+
131
+ /**********************************************************************
132
+ * Converting Floats *
133
+ **********************************************************************/
134
+
135
+ VALUE r_gmpf_to_d(VALUE self)
136
+ {
137
+ MP_FLOAT *self_val;
138
+ mpf_get_struct(self, self_val);
139
+
140
+ return rb_float_new(mpf_get_d(self_val));
141
+ }
142
+
143
+ /*
144
+ * Document-method: to_s
145
+ *
146
+ * call-seq:
147
+ * float.to_s
148
+ *
149
+ * Returns the decimal representation of +float+, as a string.
150
+ */
151
+ VALUE r_gmpf_to_s(VALUE self)
152
+ {
153
+ MP_FLOAT *self_val;
154
+ char *str, *str2;
155
+ VALUE res;
156
+ mp_exp_t exponent;
157
+
158
+ mpf_get_struct(self, self_val);
159
+
160
+ str = mpf_get_str(NULL, &exponent, 10, 0, self_val);
161
+ if ((strcmp(str, "NaN") == 0) ||
162
+ (strcmp(str, "Inf") == 0) ||
163
+ (strcmp(str, "-Inf") == 0))
164
+ {
165
+ res = rb_str_new2(str);
166
+ }
167
+ else
168
+ {
169
+ if (str[0] == '-')
170
+ __gmp_asprintf(&str2, "-0.%se%+ld", str+1, exponent);
171
+ else
172
+ __gmp_asprintf(&str2, "0.%se%+ld", str, exponent);
173
+ res = rb_str_new2(str2);
174
+ free(str2);
175
+ }
176
+ free(str);
177
+ return res;
178
+ }
179
+
180
+
181
+ /**********************************************************************
182
+ * Float Arithmetic *
183
+ **********************************************************************/
184
+
185
+ /*
186
+ * call-seq:
187
+ * float + other
188
+ *
189
+ * Returns the sum of +float+ and +other+. +other+ can be
190
+ * * GMP::Z
191
+ * * Fixnum
192
+ * * GMP::Q
193
+ * * GMP::F
194
+ * * Bignum
195
+ * * Float
196
+ */
197
+ VALUE r_gmpf_add(VALUE self, VALUE arg)
198
+ {
199
+ MP_FLOAT *self_val, *res_val, *arg_val_f;
200
+ MP_RAT *arg_val_q;
201
+ MP_INT *arg_val_z;
202
+ VALUE res;
203
+ unsigned long prec;
204
+
205
+ mpf_get_struct_prec (self, self_val, prec);
206
+
207
+ if (GMPF_P(arg)) {
208
+ mpf_get_struct (arg, arg_val_f);
209
+ prec_max(prec, arg_val_f);
210
+ mpf_make_struct_init(res, res_val, prec);
211
+ mpf_add(res_val, self_val, arg_val_f);
212
+ } else if (GMPQ_P(arg)) {
213
+ mpq_get_struct (arg, arg_val_q);
214
+ mpf_make_struct_init(res, res_val, prec);
215
+ mpf_set_q (res_val, arg_val_q);
216
+ mpf_add (res_val, res_val, self_val);
217
+ } else if (GMPZ_P(arg)) {
218
+ mpz_get_struct (arg, arg_val_z);
219
+ mpf_make_struct_init(res, res_val, prec);
220
+ mpf_set_z (res_val, arg_val_z);
221
+ mpf_add (res_val, res_val, self_val);
222
+ } else if (FLOAT_P(arg)) {
223
+ mpf_make_struct_init(res, res_val, prec);
224
+ mpf_set_d (res_val, NUM2DBL(arg));
225
+ mpf_add (res_val, res_val, self_val);
226
+ } else if (FIXNUM_P(arg)) { // _ui with sign control instead ?
227
+ mpf_make_struct_init(res, res_val, prec);
228
+ mpf_set_si (res_val, FIX2INT(arg));
229
+ mpf_add (res_val, res_val, self_val);
230
+ } else if (BIGNUM_P(arg)) {
231
+ mpz_temp_from_bignum(arg_val_z, arg);
232
+ mpf_make_struct_init(res, res_val, prec);
233
+ mpf_set_z (res_val, arg_val_z);
234
+ mpf_add (res_val, res_val, self_val);
235
+ mpz_temp_free(arg_val_z);
236
+ } else {
237
+ typeerror(ZQFXBD);
238
+ }
239
+
240
+ return res;
241
+ }
242
+
243
+ /*
244
+ * call-seq:
245
+ * float1 - float2
246
+ *
247
+ * Subtracts +float2+ from +float1+. +float2+ can be
248
+ * * GMP::Z
249
+ * * Fixnum
250
+ * * GMP::Q
251
+ * * GMP::F
252
+ * * Bignum
253
+ * * Float
254
+ */
255
+ VALUE r_gmpf_sub(VALUE self, VALUE arg)
256
+ {
257
+ MP_FLOAT *self_val, *res_val, *arg_val_f;
258
+ MP_RAT *arg_val_q;
259
+ MP_INT *arg_val_z;
260
+ VALUE res;
261
+ unsigned long prec;
262
+
263
+ mpf_get_struct_prec (self, self_val, prec);
264
+
265
+ if (GMPF_P(arg)) {
266
+ mpf_get_struct(arg, arg_val_f);
267
+ prec_max(prec, arg_val_f);
268
+ mpf_make_struct_init(res, res_val, prec);
269
+ mpf_sub(res_val, self_val, arg_val_f);
270
+ } else if (GMPQ_P(arg)) {
271
+ mpq_get_struct(arg, arg_val_q);
272
+ mpf_make_struct_init(res, res_val, prec);
273
+ mpf_set_q(res_val, arg_val_q);
274
+ mpf_sub(res_val, self_val, res_val);
275
+ } else if (GMPZ_P(arg)) {
276
+ mpz_get_struct(arg, arg_val_z);
277
+ mpf_make_struct_init(res, res_val, prec);
278
+ mpf_set_z(res_val, arg_val_z);
279
+ mpf_sub(res_val, self_val, res_val);
280
+ } else if (FLOAT_P(arg)) {
281
+ mpf_make_struct_init(res, res_val, prec);
282
+ mpf_set_d(res_val, NUM2DBL(arg));
283
+ mpf_sub(res_val, self_val, res_val);
284
+ } else if (FIXNUM_P(arg)) { // _ui with sign control instead ?
285
+ mpf_make_struct_init(res, res_val, prec);
286
+ mpf_set_si(res_val, FIX2INT(arg));
287
+ mpf_sub(res_val, self_val, res_val);
288
+ } else if (BIGNUM_P(arg)) {
289
+ mpz_temp_from_bignum(arg_val_z, arg);
290
+ mpf_make_struct_init(res, res_val, prec);
291
+ mpf_set_z(res_val, arg_val_z);
292
+ mpf_sub(res_val, self_val, res_val);
293
+ mpz_temp_free(arg_val_z);
294
+ } else {
295
+ typeerror(ZQFXBD);
296
+ }
297
+
298
+ return res;
299
+ }
300
+
301
+ /*
302
+ * call-seq:
303
+ * float * other
304
+ *
305
+ * Returns the product of +float+ and +other+. +other+ can be
306
+ * * GMP::Z
307
+ * * Fixnum
308
+ * * GMP::Q
309
+ * * GMP::F
310
+ * * Bignum
311
+ * * Float
312
+ */
313
+ VALUE r_gmpf_mul(VALUE self, VALUE arg)
314
+ {
315
+ MP_FLOAT *self_val, *res_val, *arg_val_f;
316
+ MP_RAT *arg_val_q;
317
+ MP_INT *arg_val_z;
318
+ VALUE res;
319
+ unsigned long prec;
320
+
321
+ mpf_get_struct_prec (self, self_val, prec);
322
+
323
+ if (GMPF_P(arg)) {
324
+ mpf_get_struct(arg, arg_val_f);
325
+ prec_max(prec, arg_val_f);
326
+ mpf_make_struct_init(res, res_val, prec);
327
+ mpf_mul(res_val, self_val, arg_val_f);
328
+ } else if (GMPQ_P(arg)) {
329
+ mpq_get_struct(arg, arg_val_q);
330
+ mpf_make_struct_init(res, res_val, prec);
331
+ mpf_set_q(res_val, arg_val_q);
332
+ mpf_mul(res_val, self_val, res_val);
333
+ } else if (GMPZ_P(arg)) {
334
+ mpz_get_struct(arg, arg_val_z);
335
+ mpf_make_struct_init(res, res_val, prec);
336
+ mpf_set_z(res_val, arg_val_z);
337
+ mpf_mul(res_val, self_val, res_val);
338
+ } else if (FLOAT_P(arg)) {
339
+ mpf_make_struct_init(res, res_val, prec);
340
+ mpf_set_d(res_val, NUM2DBL(arg));
341
+ mpf_mul(res_val, self_val, res_val);
342
+ } else if (FIXNUM_P(arg)) { // _ui with sign control instead ?
343
+ mpf_make_struct_init(res, res_val, prec);
344
+ mpf_set_si(res_val, FIX2INT(arg));
345
+ mpf_mul(res_val, self_val, res_val);
346
+ } else if (BIGNUM_P(arg)) {
347
+ mpz_temp_from_bignum(arg_val_z, arg);
348
+ mpf_make_struct_init(res, res_val, prec);
349
+ mpf_set_z(res_val, arg_val_z);
350
+ mpf_mul(res_val, res_val, self_val);
351
+ mpz_temp_free(arg_val_z);
352
+ } else {
353
+ typeerror(ZQFXBD);
354
+ }
355
+
356
+ return res;
357
+ }
358
+
359
+ /*
360
+ * call-seq:
361
+ * float1 / float2
362
+ *
363
+ * Divides +float1+ by +float2+. +float2+ can be
364
+ * * GMP::Z
365
+ * * Fixnum
366
+ * * GMP::Q
367
+ * * GMP::F
368
+ * * Bignum
369
+ * * Float
370
+ */
371
+ VALUE r_gmpf_div(VALUE self, VALUE arg)
372
+ {
373
+ MP_FLOAT *self_val, *res_val, *arg_val_f;
374
+ MP_RAT *arg_val_q;
375
+ MP_INT *arg_val_z;
376
+ VALUE res;
377
+ unsigned long prec;
378
+
379
+ mpf_get_struct_prec (self, self_val, prec);
380
+
381
+ if (GMPF_P(arg)) {
382
+ mpf_get_struct (arg, arg_val_f);
383
+ prec_max(prec, arg_val_f);
384
+ mpf_make_struct_init(res, res_val, prec);
385
+ mpf_div(res_val, self_val, arg_val_f);
386
+ } else if (GMPQ_P(arg)) {
387
+ mpq_get_struct (arg, arg_val_q);
388
+ mpf_make_struct_init(res, res_val, prec);
389
+ mpf_set_q (res_val, arg_val_q);
390
+ mpf_div (res_val, self_val, res_val);
391
+ } else if (GMPZ_P(arg)) {
392
+ mpz_get_struct (arg, arg_val_z);
393
+ mpf_make_struct_init(res, res_val, prec);
394
+ mpf_set_z (res_val, arg_val_z);
395
+ mpf_div (res_val, self_val, res_val);
396
+ } else if (FLOAT_P(arg)) {
397
+ mpf_make_struct_init(res, res_val, prec);
398
+ mpf_set_d (res_val, NUM2DBL(arg));
399
+ mpf_div (res_val, self_val, res_val);
400
+ } else if (FIXNUM_P(arg)) { // _ui with sign control instead ?
401
+ mpf_make_struct_init(res, res_val, prec);
402
+ mpf_set_si (res_val, FIX2INT(arg));
403
+ mpf_div (res_val, self_val, res_val);
404
+ } else if (BIGNUM_P(arg)) {
405
+ mpz_temp_from_bignum(arg_val_z, arg);
406
+ mpf_make_struct_init(res, res_val, prec);
407
+ mpf_set_z (res_val, arg_val_z);
408
+ mpf_div (res_val, self_val, res_val);
409
+ mpz_temp_free(arg_val_z);
410
+ } else {
411
+ typeerror(ZQFXBD);
412
+ }
413
+
414
+ return res;
415
+ }
416
+
417
+ /*
418
+ * Document-method: neg
419
+ *
420
+ * call-seq:
421
+ * float.neg
422
+ * -float
423
+ *
424
+ * From the GMP Manual:
425
+ *
426
+ * Returns -+float+.
427
+ */
428
+ /*
429
+ * Document-method: neg!
430
+ *
431
+ * call-seq:
432
+ * float.neg!
433
+ *
434
+ * Sets +float+ to -+float+.
435
+ */
436
+ DEFUN_FLOAT2FLOAT(neg,mpf_neg)
437
+ /*
438
+ * Document-method: abs
439
+ *
440
+ * call-seq:
441
+ * float.abs
442
+ *
443
+ * From the GMP Manual:
444
+ *
445
+ * Returns the absolute value of +float+.
446
+ */
447
+ /*
448
+ * Document-method: abs!
449
+ *
450
+ * call-seq:
451
+ * float.abs!
452
+ *
453
+ * Sets +float+ to the absolute value of +float+.
454
+ */
455
+ DEFUN_FLOAT2FLOAT(abs,mpf_abs)
456
+
457
+
458
+ /**********************************************************************
459
+ * Float Comparison *
460
+ **********************************************************************/
461
+
462
+ int mpf_cmp_value(MP_FLOAT *self_val, VALUE arg)
463
+ {
464
+ MP_FLOAT *arg_val;
465
+ int result;
466
+
467
+ if (GMPF_P(arg)) {
468
+ mpf_get_struct(arg,arg_val);
469
+ return mpf_cmp (self_val, arg_val);
470
+ } else {
471
+ mpf_temp_init(arg_val, mpf_get_prec (self_val));
472
+ mpf_set_value (arg_val, arg);
473
+ result = mpf_cmp (self_val, arg_val);
474
+ mpf_temp_free(arg_val);
475
+ return result;
476
+ }
477
+ }
478
+
479
+ /* what does really "equal" mean ? it's not obvious */
480
+ VALUE r_gmpf_eq(VALUE self, VALUE arg)
481
+ {
482
+ MP_FLOAT *self_val;
483
+ mpf_get_struct (self,self_val);
484
+ return (mpf_cmp_value(self_val, arg) == 0) ? Qtrue : Qfalse;
485
+ }
486
+
487
+ VALUE r_gmpf_cmp(VALUE self, VALUE arg)
488
+ {
489
+ MP_FLOAT *self_val;
490
+ int res;
491
+ mpf_get_struct(self,self_val);
492
+ res = mpf_cmp_value(self_val, arg);
493
+ if (res > 0)
494
+ return INT2FIX(1);
495
+ else if (res == 0)
496
+ return INT2FIX(0);
497
+ else
498
+ return INT2FIX(-1);
499
+ }
500
+
501
+ DEFUN_FLOAT_CMP(lt,<)
502
+ DEFUN_FLOAT_CMP(le,<=)
503
+ DEFUN_FLOAT_CMP(gt,>)
504
+ DEFUN_FLOAT_CMP(ge,>=)
505
+
506
+
507
+ /**********************************************************************
508
+ * _unsorted_ *
509
+ **********************************************************************/
510
+
511
+ DEFUN_FLOAT2FLOAT(floor,mpf_floor)
512
+ DEFUN_FLOAT2FLOAT(trunc,mpf_trunc)
513
+ DEFUN_FLOAT2FLOAT(ceil,mpf_ceil)
514
+
515
+ /*
516
+ * call-seq:
517
+ * float.sgn
518
+ *
519
+ * From the GMP Manual:
520
+ *
521
+ * Returns +1 if +float+ > 0, 0 if +float+ == 0, and -1 if +float+ < 0.
522
+ */
523
+ VALUE r_gmpf_sgn(VALUE self)
524
+ {
525
+ MP_FLOAT *self_val;
526
+ mpf_get_struct(self, self_val);
527
+ return INT2FIX(mpf_sgn(self_val));
528
+ }
529
+
530
+ VALUE r_gmpf_get_prec(VALUE self)
531
+ {
532
+ MP_FLOAT *self_val;
533
+ mpf_get_struct(self, self_val);
534
+ return INT2NUM(mpf_get_prec(self_val));
535
+ }
536
+
537
+
538
+ void init_gmpf()
539
+ {
540
+ mGMP = rb_define_module("GMP");
541
+ // rb_define_module_function(mGMP, "Z", r_gmpmod_z, -1);
542
+ // rb_define_module_function(mGMP, "Q", r_gmpmod_q, -1);
543
+ rb_define_module_function(mGMP, "F", r_gmpmod_f, -1);
544
+
545
+ cGMP_F = rb_define_class_under (mGMP, "F", rb_cNumeric);
546
+
547
+
548
+ // Initializing, Assigning Floats
549
+ rb_define_singleton_method(cGMP_F, "new", r_gmpfsg_new, -1);
550
+ rb_define_method(cGMP_F, "initialize", r_gmpf_initialize, -1);
551
+
552
+ // Converting Floats
553
+ rb_define_method(cGMP_F, "to_s", r_gmpf_to_s, 0);
554
+ rb_define_method(cGMP_F, "to_d", r_gmpf_to_d, 0);
555
+ rb_define_alias(cGMP_F, "to_f", "to_d");
556
+
557
+ // Float Arithmetic
558
+ rb_define_method(cGMP_F, "+", r_gmpf_add, 1);
559
+ rb_define_method(cGMP_F, "-", r_gmpf_sub, 1);
560
+ rb_define_method(cGMP_F, "*", r_gmpf_mul, 1);
561
+ rb_define_method(cGMP_F, "/", r_gmpf_div, 1);
562
+ rb_define_method(cGMP_F, "-@", r_gmpf_neg, 0);
563
+ rb_define_method(cGMP_F, "neg!", r_gmpf_neg_self, 0);
564
+ rb_define_method(cGMP_F, "abs", r_gmpf_abs, 0);
565
+ rb_define_method(cGMP_F, "abs!", r_gmpf_abs_self, 0);
566
+
567
+ // Float Comparison
568
+ rb_define_method(cGMP_F, "<=>", r_gmpf_cmp, 1);
569
+ rb_define_method(cGMP_F, ">", r_gmpf_cmp_gt, 1);
570
+ rb_define_method(cGMP_F, ">=", r_gmpf_cmp_ge, 1);
571
+ rb_define_method(cGMP_F, "<", r_gmpf_cmp_lt, 1);
572
+ rb_define_method(cGMP_F, "<=", r_gmpf_cmp_le, 1);
573
+ rb_define_method(cGMP_F, "==", r_gmpf_eq, 1);
574
+
575
+ // _unsorted_
576
+ rb_define_method(cGMP_F, "floor", r_gmpf_floor, 0);
577
+ rb_define_method(cGMP_F, "floor!", r_gmpf_floor_self, 0);
578
+ rb_define_method(cGMP_F, "ceil", r_gmpf_ceil, 0);
579
+ rb_define_method(cGMP_F, "ceil!", r_gmpf_ceil_self, 0);
580
+ rb_define_method(cGMP_F, "trunc", r_gmpf_trunc, 0);
581
+ rb_define_method(cGMP_F, "trunc!", r_gmpf_trunc_self, 0);
582
+ rb_define_method(cGMP_F, "sgn", r_gmpf_sgn, 0);
583
+ rb_define_method(cGMP_F, "prec", r_gmpf_get_prec, 0);
584
+ }