2 #include <mruby/class.h>
3 #include <mruby/string.h>
4 #include <mruby/numeric.h>
11 #if MRB_INT_MAX <= INTPTR_MAX
13 #define RATIONAL_USE_ISTRUCT
15 #include <mruby/istruct.h>
17 #define rational_ptr(mrb, v) (struct mrb_rational*)mrb_istruct_ptr(v)
20 rational_alloc(mrb_state *mrb, struct RClass *c, struct mrb_rational **p)
24 s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c);
25 *p = (struct mrb_rational*)s->inline_data;
27 return (struct RBasic*)s;
32 #include <mruby/data.h>
34 static const struct mrb_data_type mrb_rational_type = {"Rational", mrb_free};
37 rational_alloc(mrb_state *mrb, struct RClass *c, struct mrb_rational **p)
41 Data_Make_Struct(mrb, c, struct mrb_rational, &mrb_rational_type, *p, d);
43 return (struct RBasic*)d;
46 static struct mrb_rational*
47 rational_ptr(mrb_state *mrb, mrb_value v)
49 struct mrb_rational *p;
51 p = DATA_GET_PTR(mrb, v, &mrb_rational_type, struct mrb_rational);
53 mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized rational");
60 rational_numerator(mrb_state *mrb, mrb_value self)
62 struct mrb_rational *p = rational_ptr(mrb, self);
63 return mrb_fixnum_value(p->numerator);
67 rational_denominator(mrb_state *mrb, mrb_value self)
69 struct mrb_rational *p = rational_ptr(mrb, self);
70 return mrb_fixnum_value(p->denominator);
74 rational_new(mrb_state *mrb, mrb_int numerator, mrb_int denominator)
76 struct RClass *c = mrb_class_get(mrb, "Rational");
77 struct mrb_rational *p;
78 struct RBasic *rat = rational_alloc(mrb, c, &p);
79 p->numerator = numerator;
80 p->denominator = denominator;
81 MRB_SET_FROZEN_FLAG(rat);
82 return mrb_obj_value(rat);
86 rational_s_new(mrb_state *mrb, mrb_value self)
88 mrb_int numerator, denominator;
90 #ifdef MRB_WITHOUT_FLOAT
91 mrb_get_args(mrb, "ii", &numerator, &denominator);
94 #define DROP_PRECISION(f, num, denom) \
96 while (f < (mrb_float)MRB_INT_MIN || f > (mrb_float)MRB_INT_MAX) { \
102 mrb_value numv, denomv;
104 mrb_get_args(mrb, "oo", &numv, &denomv);
105 if (mrb_fixnum_p(numv)) {
106 numerator = mrb_fixnum(numv);
108 if (mrb_fixnum_p(denomv)) {
109 denominator = mrb_fixnum(denomv);
112 mrb_float denomf = mrb_to_flo(mrb, denomv);
114 DROP_PRECISION(denomf, numerator, denomf);
115 denominator = (mrb_int)denomf;
119 mrb_float numf = mrb_to_flo(mrb, numv);
121 if (mrb_fixnum_p(denomv)) {
122 denominator = mrb_fixnum(denomv);
125 mrb_float denomf = mrb_to_flo(mrb, denomv);
127 DROP_PRECISION(denomf, numf, denomf);
128 denominator = (mrb_int)denomf;
131 DROP_PRECISION(numf, numf, denominator);
132 numerator = (mrb_int)numf;
136 return rational_new(mrb, numerator, denominator);
139 #ifndef MRB_WITHOUT_FLOAT
141 rational_to_f(mrb_state *mrb, mrb_value self)
143 struct mrb_rational *p = rational_ptr(mrb, self);
144 mrb_float f = (mrb_float)p->numerator / (mrb_float)p->denominator;
146 return mrb_float_value(mrb, f);
151 rational_to_i(mrb_state *mrb, mrb_value self)
153 struct mrb_rational *p = rational_ptr(mrb, self);
154 if (p->denominator == 0) {
155 mrb_raise(mrb, mrb->eStandardError_class, "divided by 0");
157 return mrb_fixnum_value(p->numerator / p->denominator);
161 rational_to_r(mrb_state *mrb, mrb_value self)
167 rational_negative_p(mrb_state *mrb, mrb_value self)
169 struct mrb_rational *p = rational_ptr(mrb, self);
170 if (p->numerator < 0) {
171 return mrb_true_value();
173 return mrb_false_value();
177 fix_to_r(mrb_state *mrb, mrb_value self)
179 return rational_new(mrb, mrb_fixnum(self), 1);
182 void mrb_mruby_rational_gem_init(mrb_state *mrb)
186 rat = mrb_define_class(mrb, "Rational", mrb_class_get(mrb, "Numeric"));
187 #ifdef RATIONAL_USE_ISTRUCT
188 MRB_SET_INSTANCE_TT(rat, MRB_TT_ISTRUCT);
189 mrb_assert(sizeof(struct mrb_rational) < ISTRUCT_DATA_SIZE);
191 MRB_SET_INSTANCE_TT(rat, MRB_TT_DATA);
193 mrb_undef_class_method(mrb, rat, "new");
194 mrb_define_class_method(mrb, rat, "_new", rational_s_new, MRB_ARGS_REQ(2));
195 mrb_define_method(mrb, rat, "numerator", rational_numerator, MRB_ARGS_NONE());
196 mrb_define_method(mrb, rat, "denominator", rational_denominator, MRB_ARGS_NONE());
197 #ifndef MRB_WITHOUT_FLOAT
198 mrb_define_method(mrb, rat, "to_f", rational_to_f, MRB_ARGS_NONE());
200 mrb_define_method(mrb, rat, "to_i", rational_to_i, MRB_ARGS_NONE());
201 mrb_define_method(mrb, rat, "to_r", rational_to_r, MRB_ARGS_NONE());
202 mrb_define_method(mrb, rat, "negative?", rational_negative_p, MRB_ARGS_NONE());
203 mrb_define_method(mrb, mrb->fixnum_class, "to_r", fix_to_r, MRB_ARGS_NONE());
207 mrb_mruby_rational_gem_final(mrb_state* mrb)