2 Copyright (C) 2008, The Perl Foundation.
9 src/dynpmc/rational.pmc - Rational numbers PMC
13 Rational is currently going to get implemented. It uses the GNU Multiple Precision (GMP) library,
14 like BigInt, because implementation with integers would be too unstable and inaccurate.
16 'LispRational' will subclass this.
18 You may use Rational with any of parrot's basic data types as well as with String-, Integer- and
23 Currently C<rational.pmc> only has some C<static> functions for code sharing.
31 #include "parrot/has_header.h"
35 typedef struct RATIONAL {
38 # define RT(x) ((RATIONAL*) PMC_struct_val(x))->q
43 #define RAISE_EXCEPTION Parrot_ex_throw_from_c_args(interp, NULL, \
44 EXCEPTION_LIBRARY_NOT_LOADED, "GNU Multiple Precision library not found.");
48 =item * static STRING *rat_get_string_to_base(PARROT_INTERP, PMC *self, int base)
50 Returns a string representation of a Rational-PMC to a certain base.
55 static STRING *rat_get_string_to_base(PARROT_INTERP, PMC *self, int base) {
58 char *cstr = mpq_get_str(NULL, (int) base, RT(self));
59 pstr = string_from_cstring(interp, cstr, 0);
60 string_cstring_free(cstr);
69 =item * static void rat_add_integer(PARROT_INTERP, PMC *self, int value, PMC *dest)
71 Adds an integer "value" to a Rational-PMC and stores the result in (another) Rational-PMC.
76 static void rat_add_integer(PARROT_INTERP, PMC *self, int value, PMC *dest) {
82 VTABLE_morph(interp, dest, self->vtable->base_type);
85 dest = pmc_new(interp, self->vtable->base_type);
89 mpq_set_si(t, (int) value, 1);
90 mpq_add(RT(dest), RT(self), t);
99 =item * static void rat_add_float(PARROT_INTERP, PMC *self, double value, PMC *dest)
101 Adds a float "value" to a Rational-PMC and stores the result in (another) Rational-PMC. "value" is
102 first conveted to a rational using GMPs mpq_set_d-function. This is meant to be exact.
107 static void rat_add_float(PARROT_INTERP, PMC *self, double value, PMC *dest) {
108 #ifdef PARROT_HAS_GMP
112 VTABLE_morph(interp, dest, self->vtable->base_type);
114 dest = pmc_new(interp, self->vtable->base_type);
117 mpq_set_d(t, (double) value);
118 mpq_add(RT(dest), RT(self), t);
127 =item * static void rat_multiply_integer(PARROT_INTERP, PMC *self, int value, PMC *dest)
129 Multiplys a Rational-PMC with an integer "value" and stores the result in (another) Rational-PMC.
134 static void rat_multiply_integer(PARROT_INTERP, PMC *self, int value, PMC *dest) {
135 #ifdef PARROT_HAS_GMP
137 VTABLE_morph(interp, dest, self->vtable->base_type);
139 dest = pmc_new(interp, self->vtable->base_type);
141 mpz_mul_ui(mpq_numref(RT(dest)), mpq_numref(RT(self)), (unsigned int) value);
142 mpq_set_den(RT(dest), mpq_denref(RT(self)));
150 =item * static void rat_multiply_float(PARROT_INTERP, PMC *self, double value, PMC *dest)
152 Multiplies a Rational-PMC with a float "value" and stores the result in (another) Rational-PMC.
157 static void rat_multiply_float(PARROT_INTERP, PMC *self, double value, PMC *dest) {
158 #ifdef PARROT_HAS_GMP
162 VTABLE_morph(interp, dest, self->vtable->base_type);
164 dest = pmc_new(interp, self->vtable->base_type);
167 mpq_set_d(t, (double) value);
168 mpq_mul(RT(dest), RT(self), t);
177 =item * static void rat_divide_integer(PARROT_INTERP, PMC *self, int value, PMC *dest)
179 Divides a Rational-PMC through an integer "value" and stores the result in (another) Rational-PMC.
184 static void rat_divide_integer(PARROT_INTERP, PMC *self, int value, PMC *dest) {
185 #ifdef PARROT_HAS_GMP
189 VTABLE_morph(interp, dest, self->vtable->base_type);
191 dest = pmc_new(interp, self->vtable->base_type);
194 mpq_set_si(t, (int) value, 1);
195 mpq_div(RT(dest), RT(self), t);
204 =item * static void rat_divide_float(PARROT_INTERP, PMC *self, double value, PMC *dest)
206 Divides a Rational-PMC through a float "value" and stores the result in (another) Rational-PMC.
211 static void rat_divide_float(PARROT_INTERP, PMC *self, double value, PMC *dest) {
212 #ifdef PARROT_HAS_GMP
216 VTABLE_morph(interp, dest, self->vtable->base_type);
218 dest = pmc_new(interp, self->vtable->base_type);
221 mpq_set_d(t, (double) value);
222 mpq_div(RT(dest), RT(self), t);
231 =item * static void rat_power_int(PARROT_INTERP, PMC *self, int value, PMC *dest)
233 Calculates the power of a Rational-PMC to an exponent value and stores the result in (another)
239 static void rat_power_int(PARROT_INTERP, PMC *self, int value, PMC *dest) {
240 #ifdef PARROT_HAS_GMP
244 VTABLE_morph(interp, dest, self->vtable->base_type);
246 dest = pmc_new(interp, self->vtable->base_type);
248 mpq_get_num(t, RT(self));
249 mpz_pow_ui(t, t, (unsigned int) value);
250 mpq_set_num(RT(dest), t);
253 mpq_get_den(t, RT(self));
254 mpz_pow_ui(t, t, (unsigned int) value);
255 mpq_set_den(RT(dest), t);
270 pmclass Rational dynpmc provides scalar {
275 The DynPMC Rational has the following methods. Note, that all methods depend on GMP. If GMP is not
276 available, an exception is thrown in almost all cases. The only exception is the version-method.
280 =item C<METHOD version()>
282 Returns the version of GNU Multiple Precision library. Returns 0.0.0, if GMP is not available.
289 #ifdef PARROT_HAS_GMP
290 version = string_from_cstring(INTERP, gmp_version, 0);
292 version = string_from_cstring(INTERP, "0.0.0", 0);
294 RETURN(STRING *version);
305 #ifdef PARROT_HAS_GMP
306 PMC_struct_val(SELF) = malloc(sizeof (RATIONAL));
308 PObj_active_destroy_SET(SELF);
310 PMC_struct_val(SELF) = NULL;
316 =item C<void clone()>
321 VTABLE PMC *clone() {
322 #ifdef PARROT_HAS_GMP
324 PMC *ret = pmc_new(INTERP, SELF->vtable->base_type);
325 mpq_get_num(num, RT(SELF));
326 mpq_get_den(den, RT(SELF));
327 mpq_set_num(RT(ret), num);
328 mpq_set_den(RT(ret), den);
339 =item C<void destroy()>
344 VTABLE void destroy() {
345 #ifdef PARROT_HAS_GMP
347 mem_sys_free(PMC_struct_val(SELF));
355 =item C<void set_integer_native(INTVAL)>
360 VTABLE void set_integer_native(INTVAL value) {
361 #ifdef PARROT_HAS_GMP
362 mpq_set_si(RT(SELF), (signed int) value, 1);
363 mpq_canonicalize(RT(SELF));
371 =item C<void set_number_native(FLOATVAL)>
376 VTABLE void set_number_native(FLOATVAL value) {
377 #ifdef PARROT_HAS_GMP
378 mpq_set_d(RT(SELF), (double) value);
379 mpq_canonicalize(RT(SELF));
387 =item C<void set_string_native(STRING*)>
392 VTABLE void set_string_native(STRING *value) {
393 #ifdef PARROT_HAS_GMP
394 char *cstr = string_to_cstring(INTERP, value);
395 mpq_set_str(RT(SELF), cstr, 0);
396 mpq_canonicalize(RT(SELF));
397 string_cstring_free(cstr);
405 =item C<void set_string_keyed_int(INTVAL base, STRING *value)>
410 VTABLE void set_string_keyed_int(INTVAL base, STRING *value) {
411 #ifdef PARROT_HAS_GMP
412 char *cstr = string_to_cstring(INTERP, value);
413 mpq_set_str(RT(SELF), cstr, (int) base);
414 mpq_canonicalize(RT(SELF));
415 string_cstring_free(cstr);
424 =item C<INTVAL get_integer()>
429 VTABLE INTVAL get_integer() {
430 #ifdef PARROT_HAS_GMP
433 mpz_tdiv_q(q, mpq_numref(RT(SELF)), mpq_denref(RT(SELF)));
434 if (mpz_fits_slong_p(q)) {
435 INTVAL ret = (INTVAL) mpz_get_si(q);
441 Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
442 "Rational, get_integer(): Number is too big.");
451 =item C<get_number()>
456 VTABLE FLOATVAL get_number() {
457 #ifdef PARROT_HAS_GMP
459 d = mpq_get_d(RT(SELF));
473 VTABLE INTVAL get_bool() {
474 #ifdef PARROT_HAS_GMP
475 if (mpq_cmp_si(RT(SELF), 0, 0))
485 =item C<STRING *get_string()>
490 VTABLE STRING *get_string() {
491 #ifdef PARROT_HAS_GMP
492 return rat_get_string_to_base(INTERP, SELF, 10);
500 =item C<STRING *get_string_keyed_int(INTVAL base)>
505 VTABLE STRING *get_string_keyed_int(INTVAL base) {
506 #ifdef PARROT_HAS_GMP
507 return rat_get_string_to_base(INTERP, SELF, (int) base);
515 =item C<void increment()>
520 VTABLE void increment() {
521 #ifdef PARROT_HAS_GMP
522 mpz_add(mpq_numref(RT(SELF)), mpq_numref(RT(SELF)), mpq_denref(RT(SELF)));
523 mpq_canonicalize(RT(SELF));
531 =item C<void decrement()>
536 VTABLE void decrement() {
537 #ifdef PARROT_HAS_GMP
538 mpz_sub(mpq_numref(RT(SELF)), mpq_numref(RT(SELF)), mpq_denref(RT(SELF)));
539 mpq_canonicalize(RT(SELF));
547 =item C<PMC *add(PMC* value, PMC* dest)>
549 Adds Integer-, Float- or Rational-PMCs to SELF and stores them in dest.
554 VTABLE PMC *add(PMC* value, PMC* dest) {
556 rat_add_integer(INTERP, SELF, PMC_int_val(value), dest);
560 rat_add_float(INTERP, SELF, PMC_num_val(value), dest);
564 #ifdef PARROT_HAS_GMP
566 VTABLE_morph(INTERP, dest, SELF->vtable->base_type);
568 dest = pmc_new(INTERP, SELF->vtable->base_type);
570 mpq_add(RT(dest), RT(SELF), RT(value));
577 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_UNIMPLEMENTED,
578 "Rational, add: Not implemented (yet).");
584 =item C<void i_add(PMC *value)>
589 VTABLE void i_add(PMC *value) {
591 rat_add_integer(INTERP, SELF, (int) PMC_int_val(value), SELF);
594 rat_add_float(INTERP, SELF, (double) PMC_num_val(value), SELF);
597 #ifdef PARROT_HAS_GMP
598 mpq_add(RT(SELF), RT(SELF), RT(value));
604 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_UNIMPLEMENTED,
605 "Rational, i_add: Not implemented (yet).");
611 =item C<PMC *add_int(INTVAL value, PMC* dest)>
616 VTABLE PMC *add_int(INTVAL value, PMC* dest) {
617 rat_add_integer(INTERP, SELF, (int) value, dest);
623 =item C<void i_add_int(INTVAL value)>
628 VTABLE void i_add_int(INTVAL value) {
629 rat_add_integer(INTERP, SELF, (int) value, SELF);
634 =item C<PMC *add_float(FLOATVAL value, PMC* dest)>
639 VTABLE PMC *add_float(FLOATVAL value, PMC* dest) {
640 rat_add_float(INTERP, SELF, (double) value, dest);
646 =item C<void i_add_float(FLOATVAL value)>
651 VTABLE void i_add_float(FLOATVAL value) {
652 rat_add_float(INTERP, SELF, (double) value, SELF);
657 =item C<PMC *subtract(PMC* value, PMC* dest)>
662 VTABLE PMC *subtract(PMC* value, PMC* dest) {
664 rat_add_integer(INTERP, SELF, -((int) PMC_int_val(value)), dest);
668 rat_add_float(INTERP, SELF, - ((double) PMC_num_val(value)), dest);
672 #ifdef PARROT_HAS_GMP
674 VTABLE_morph(INTERP, dest, SELF->vtable->base_type);
676 dest = pmc_new(INTERP, SELF->vtable->base_type);
678 mpq_sub(RT(dest), RT(SELF), RT(value));
685 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_UNIMPLEMENTED,
686 "Rational, subtract: Not implemented (yet).");
692 =item C<void i_subtract(PMC *value)>
697 VTABLE void i_subtract(PMC *value) {
699 rat_add_integer(INTERP, SELF, -((int) PMC_int_val(value)), SELF);
702 rat_add_float(INTERP, SELF, - ((double) PMC_num_val(value)), SELF);
705 #ifdef PARROT_HAS_GMP
706 mpq_sub(RT(SELF), RT(SELF), RT(value));
712 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_UNIMPLEMENTED,
713 "Rational, i_subtract: Not implemented (yet).");
719 =item C<PMC *subtract_int(INTVAL value, PMC* dest)>
724 VTABLE PMC *subtract_int(INTVAL value, PMC* dest) {
725 rat_add_integer(INTERP, SELF, -((int) value), dest);
731 =item C<void i_subtract_int(INTVAL value)>
736 VTABLE void i_subtract_int(INTVAL value) {
737 rat_add_integer(INTERP, SELF, -((int) value), SELF);
742 =item C<PMC *subtract_float(FLOATVAL value, PMC* dest)>
747 VTABLE PMC *subtract_float(FLOATVAL value, PMC* dest) {
748 rat_add_float(INTERP, SELF, -((double) value), dest);
754 =item C<void i_subtract_float(FLOATVAL value)>
759 VTABLE void i_subtract_float(FLOATVAL value) {
760 rat_add_float(INTERP, SELF, -((double) value), SELF);
765 =item C<PMC *multiply(PMC* value, PMC* dest)>
770 VTABLE PMC *multiply(PMC* value, PMC* dest) {
772 rat_multiply_integer(INTERP, SELF, (int) PMC_int_val(value), dest);
776 rat_multiply_float(INTERP, SELF, (double) PMC_num_val(value), dest);
780 #ifdef PARROT_HAS_GMP
782 VTABLE_morph(INTERP, dest, SELF->vtable->base_type);
784 dest = pmc_new(INTERP, SELF->vtable->base_type);
786 mpq_mul(RT(dest), RT(SELF), RT(value));
793 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_UNIMPLEMENTED,
794 "Rational, multiply: Not implemented (yet).");
800 =item C<void i_multiply(PMC *value)>
805 VTABLE void i_multiply(PMC *value) {
807 rat_multiply_integer(INTERP, SELF, (int) PMC_int_val(value), SELF);
810 rat_multiply_float(INTERP, SELF, (double) PMC_num_val(value), SELF);
813 #ifdef PARROT_HAS_GMP
814 mpq_mul(RT(SELF), RT(SELF), RT(value));
820 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_UNIMPLEMENTED,
821 "Rational, i_multiply: Not implemented (yet).");
827 =item C<PMC *multiply_int(INTVAL value, PMC* dest)>
832 VTABLE PMC *multiply_int(INTVAL value, PMC* dest) {
833 rat_multiply_integer(INTERP, SELF, (int) value, dest);
839 =item C<void i_multiply_int(INTVAL value)>
844 VTABLE void i_multiply_int(INTVAL value) {
845 rat_multiply_integer(INTERP, SELF, (int) value, SELF);
850 =item C<PMC *multiply_float(FLOATVAL value, PMC* dest)>
855 VTABLE PMC *multiply_float(FLOATVAL value, PMC* dest) {
856 rat_multiply_float(INTERP, SELF, (double) value, dest);
862 =item C<void i_multiply_float(FLOATVAL value)>
867 VTABLE void i_multiply_float(FLOATVAL value) {
868 rat_multiply_float(INTERP, SELF, (double) value, SELF);
873 =item C<PMC *divide(PMC* value, PMC* dest)>
878 VTABLE PMC *divide(PMC* value, PMC* dest) {
880 rat_divide_integer(INTERP, SELF, (int) PMC_int_val(value), dest);
884 rat_divide_float(INTERP, SELF, (double) PMC_num_val(value), dest);
888 #ifdef PARROT_HAS_GMP
890 VTABLE_morph(INTERP, dest, SELF->vtable->base_type);
892 dest = pmc_new(INTERP, SELF->vtable->base_type);
894 mpq_div(RT(dest), RT(SELF), RT(value));
901 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_UNIMPLEMENTED,
902 "Rational, divide: Not implemented (yet).");
908 =item C<void i_divide(PMC *value)>
913 VTABLE void i_divide(PMC *value) {
915 rat_divide_integer(INTERP, SELF, (int) PMC_int_val(value), SELF);
918 rat_divide_float(INTERP, SELF, (double) PMC_num_val(value), SELF);
921 #ifdef PARROT_HAS_GMP
922 mpq_div(RT(SELF), RT(SELF), RT(value));
928 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_UNIMPLEMENTED,
929 "Rational, i_divide: Not implemented (yet).");
935 =item C<PMC *divide_int(INTVAL value, PMC* dest)>
940 VTABLE PMC *divide_int(INTVAL value, PMC* dest) {
941 rat_divide_integer(INTERP, SELF, (int) value, dest);
947 =item C<void i_divide_int(INTVAL value)>
952 VTABLE void i_divide_int(INTVAL value) {
953 rat_divide_integer(INTERP, SELF, (int) value, SELF);
958 =item C<PMC *divide_float(FLOATVAL value, PMC* dest)>
963 VTABLE PMC *divide_float(FLOATVAL value, PMC* dest) {
964 rat_divide_float(INTERP, SELF, (double) value, dest);
970 =item C<void i_divide_float(FLOATVAL value)>
975 VTABLE void i_divide_float(FLOATVAL value) {
976 rat_divide_float(INTERP, SELF, (double) value, SELF);
981 =item C<PMC *negate(PMC* dest)>
986 VTABLE PMC *neg(PMC* dest) {
987 #ifdef PARROT_HAS_GMP
989 VTABLE_morph(INTERP, dest, SELF->vtable->base_type);
991 dest = pmc_new(INTERP, SELF->vtable->base_type);
993 mpq_neg(RT(dest), RT(SELF));
1002 =item C<void i_negate()>
1007 VTABLE void i_neg() {
1008 #ifdef PARROT_HAS_GMP
1009 mpq_neg(RT(SELF), RT(SELF));
1017 =item C<PMC *absolute(PMC* dest)>
1022 VTABLE PMC *absolute(PMC* dest) {
1023 #ifdef PARROT_HAS_GMP
1025 VTABLE_morph(INTERP, dest, SELF->vtable->base_type);
1027 dest = pmc_new(INTERP, SELF->vtable->base_type);
1029 mpq_abs(RT(dest), RT(SELF));
1038 =item C<void i_absolute()>
1043 VTABLE void i_absolute() {
1044 #ifdef PARROT_HAS_GMP
1045 mpq_abs(RT(SELF), RT(SELF));
1053 =item C<INTVAL cmp(PMC *value)>
1058 VTABLE INTVAL cmp(PMC *value) {
1060 #ifdef PARROT_HAS_GMP
1061 return (INTVAL) mpq_cmp_si(RT(SELF), PMC_int_val(value), 1);
1067 #ifdef PARROT_HAS_GMP
1068 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_UNIMPLEMENTED,
1069 "This is going to get implemented soon.");
1075 #ifdef PARROT_HAS_GMP
1076 return (INTVAL) mpq_cmp(RT(SELF), RT(value));
1082 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_UNIMPLEMENTED,
1083 "cmp not implemented (yet).");
1089 =item C<INTVAL is_equal(PMC *value)>
1094 VTABLE INTVAL is_equal(PMC *value) {
1096 #ifdef PARROT_HAS_GMP
1100 mpq_set_ui(t, PMC_int_val(value), 1);
1102 eq = (INTVAL) mpq_equal(RT(SELF), RT(value));
1111 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_UNIMPLEMENTED,
1112 "Equality to floats can not be checked because of limited machine "
1113 "accuracy.\nApproximate the rational and check whether the "
1114 "difference to a value is lower\nthan an epsilon.");
1117 #ifdef PARROT_HAS_GMP
1118 return (INTVAL) mpq_equal(RT(SELF), RT(value));
1124 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_UNIMPLEMENTED,
1125 "is_equal not implemented (yet).");
1132 * c-file-style: "parrot"
1134 * vim: expandtab shiftwidth=4: