gmp 0.5.41 → 0.5.47

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/CHANGELOG +21 -0
  2. data/FEATURES.html +37 -38
  3. data/README.html +511 -0
  4. data/README.markdown +494 -0
  5. data/benchmark/divide +0 -0
  6. data/benchmark/gcd +0 -0
  7. data/benchmark/multiply +0 -0
  8. data/benchmark/multiply.fnl +0 -0
  9. data/benchmark/multiply.gc +0 -0
  10. data/benchmark/pi +0 -0
  11. data/benchmark/rsa +0 -0
  12. data/benchmark/runbench +0 -0
  13. data/benchmark/srb.sh +0 -0
  14. data/ext/gmp.c +0 -42
  15. data/ext/gmpf.c +64 -33
  16. data/ext/gmpq.c +88 -1
  17. data/ext/gmpz.c +151 -19
  18. data/ext/ruby_gmp.h +16 -10
  19. data/manual.pdf +0 -0
  20. data/manual.tex +50 -14
  21. data/test/gmp_tgcd.rb +18 -18
  22. data/test/mpfr_tcbrt.rb +1 -1
  23. data/test/mpfr_tconst_euler.rb +10 -7
  24. data/test/mpfr_tisnan.rb +1 -1
  25. data/test/mpfr_trec_sqrt.rb +1 -1
  26. data/test/mpfr_tsqrt.rb +1 -1
  27. data/test/tc_cmp.rb +7 -2
  28. data/test/tc_constants.rb +1 -1
  29. data/test/tc_division.rb +1 -1
  30. data/test/tc_f_arithmetics_coersion.rb +1 -1
  31. data/test/tc_f_precision.rb +1 -1
  32. data/test/tc_fib_fac_nextprime.rb +1 -1
  33. data/test/tc_floor_ceil_truncate.rb +1 -1
  34. data/test/tc_hashes.rb +26 -1
  35. data/test/tc_logical_roots.rb +1 -1
  36. data/test/tc_mpfr_constants.rb +1 -1
  37. data/test/tc_mpfr_functions.rb +1 -1
  38. data/test/tc_mpfr_random.rb +1 -1
  39. data/test/tc_mpfr_rounding.rb +3 -3
  40. data/test/tc_q.rb +1 -1
  41. data/test/tc_q_basic.rb +1 -1
  42. data/test/tc_random.rb +1 -1
  43. data/test/tc_sgn_neg_abs.rb +1 -1
  44. data/test/tc_swap.rb +1 -1
  45. data/test/tc_z.rb +34 -1
  46. data/test/tc_z_addmul.rb +1 -1
  47. data/test/tc_z_basic.rb +1 -1
  48. data/test/tc_z_exponentiation.rb +1 -1
  49. data/test/tc_z_functional_mappings.rb +42 -6
  50. data/test/tc_z_gcd_lcm_invert.rb +1 -1
  51. data/test/tc_z_jac_leg_rem.rb +1 -1
  52. data/test/tc_z_logic.rb +1 -1
  53. data/test/tc_z_shifts_last_bits.rb +1 -1
  54. data/test/tc_z_submul.rb +1 -1
  55. data/test/tc_z_to_dis.rb +1 -1
  56. data/test/tc_zerodivisionexceptions.rb +1 -1
  57. data/test/test_helper.rb +2 -1
  58. data/test/unit_tests.rb +1 -1
  59. metadata +70 -89
  60. data/README.rdoc +0 -450
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
data/ext/gmp.c CHANGED
@@ -20,48 +20,6 @@ void r_gmpf_free(void *ptr) { mpf_clear (ptr); free (ptr); }
20
20
  #endif
21
21
  void r_gmprandstate_free(void *ptr) { gmp_randclear (ptr); free (ptr); }
22
22
 
23
- static void mpq_str_set(MP_RAT *ROP, char *str)
24
- {
25
- int i=0;
26
-
27
- while (str[i] && str[i] != '/')
28
- i++;
29
-
30
- if (str[i])
31
- {
32
- str[i] = 0; /* You didn't see that :) */
33
- mpz_set_str (mpq_numref(ROP), str, 0);
34
- str[i] = '/';
35
- mpz_set_str (mpq_denref(ROP), str+i+1, 0);
36
- } else {
37
- mpz_set_str (mpq_numref(ROP), str, 0);
38
- mpz_set_ui (mpq_denref(ROP), 1);
39
- }
40
- mpq_canonicalize (ROP);
41
- }
42
-
43
- static VALUE r_gmpq_initialize(int argc, VALUE *argv, VALUE self)
44
- {
45
- MP_RAT *self_val, *arg_val;
46
-
47
- if (argc != 0) {
48
- mpq_get_struct(self, self_val);
49
- if (argc == 1 && GMPQ_P(argv[0])) {
50
- mpq_get_struct(argv[0], arg_val);
51
- mpq_set (self_val, arg_val);
52
- } else if (argc == 1 && STRING_P(argv[0])) {
53
- mpq_str_set (self_val, StringValuePtr(argv[0]));
54
- } else {
55
- mpz_set_value (mpq_numref(self_val), argv[0]);
56
- if (argc == 2) {
57
- mpz_set_value (mpq_denref(self_val), argv[1]);
58
- mpq_canonicalize(self_val);
59
- }
60
- }
61
- }
62
- return Qnil;
63
- }
64
-
65
23
  static VALUE r_gmpz_coerce(VALUE self, VALUE arg)
66
24
  {
67
25
  return rb_assoc_new(r_gmpzsg_new(1, &arg, cGMP_Z), self);
data/ext/gmpf.c CHANGED
@@ -50,9 +50,9 @@ static VALUE r_gmpf_cmp_##name(VALUE self, VALUE arg) \
50
50
 
51
51
  /*
52
52
  * call-seq:
53
- * GMP::R.new(arg)
53
+ * GMP::F.new(arg)
54
54
  *
55
- * Creates a new GMP::R float, with arg as its value, converting where
55
+ * Creates a new GMP::F float, with arg as its value, converting where
56
56
  * necessary.
57
57
  */
58
58
  VALUE r_gmpfsg_new(int argc, VALUE *argv, VALUE klass)
@@ -114,7 +114,7 @@ VALUE r_gmpf_initialize(int argc, VALUE *argv, VALUE self)
114
114
  mpfr_init (self_val);
115
115
  else
116
116
  mpfr_init2 (self_val, prec);
117
-
117
+
118
118
  if (STRING_P(argv[0])) {
119
119
  if (argc >= 3) {
120
120
  if (FIXNUM_P(argv[2])) {
@@ -130,7 +130,7 @@ VALUE r_gmpf_initialize(int argc, VALUE *argv, VALUE self)
130
130
  if (argc == 4) {
131
131
  // FIGURE IT OUT. ACCEPT A ROUNDING MODE!
132
132
  }
133
-
133
+
134
134
  mpf_set_value2 (self_val, arg, base);
135
135
  return Qnil;
136
136
  }
@@ -215,7 +215,7 @@ void mpf_set_value2(MP_FLOAT *self_val, VALUE arg, int base)
215
215
  int result;
216
216
 
217
217
  result = mpfr_set_str(self_val, StringValuePtr(arg), base, __gmp_default_rounding_mode);
218
-
218
+
219
219
  if (result == -1) {
220
220
  rb_raise(rb_eRuntimeError, "Badly formatted string");
221
221
  }
@@ -268,10 +268,10 @@ VALUE r_gmpf_to_s(VALUE self)
268
268
  mp_exp_t exponent;
269
269
 
270
270
  mpf_get_struct(self, self_val);
271
-
271
+
272
272
  //mpfr_sprintf(str, "%Rf", self_val);
273
273
  //res = rb_str_new2(str);
274
-
274
+
275
275
  str = mpfr_get_str(NULL, &exponent, 10, 0, self_val, __gmp_default_rounding_mode);
276
276
  if ((strcmp(str, "NaN") == 0) ||
277
277
  (strcmp(str, "Inf") == 0) ||
@@ -587,7 +587,7 @@ VALUE r_gmpf_pow(VALUE self, VALUE arg)
587
587
  {
588
588
  MP_FLOAT *self_val, *res_val;
589
589
  VALUE res;
590
-
590
+
591
591
  //unsigned long prec;
592
592
  mpfr_prec_t prec;
593
593
 
@@ -685,11 +685,11 @@ VALUE r_gmpf_div(VALUE self, VALUE arg)
685
685
  mp_rnd_t rnd_mode_value;
686
686
  MP_INT *arg_val_z;
687
687
  VALUE res;
688
-
688
+
689
689
  rb_scan_args (argc, argv, "12", &arg, &rnd_mode, &res_prec);
690
690
 
691
691
  mpf_get_struct_prec (self, self_val, prec);
692
-
692
+
693
693
  if (NIL_P (rnd_mode)) { rnd_mode_value = __gmp_default_rounding_mode; }
694
694
  else { rnd_mode_value = r_get_rounding_mode(rnd_mode); }
695
695
  if (NIL_P (res_prec)) { res_prec_value = prec; }
@@ -1107,7 +1107,7 @@ VALUE r_gmpfsg_set_default_rounding_mode(VALUE klass, VALUE arg)
1107
1107
  } else {
1108
1108
  rb_raise(rb_eTypeError, "rounding mode must be one of the rounding mode constants.");
1109
1109
  }
1110
-
1110
+
1111
1111
  switch (FIX2INT(mode)) {
1112
1112
  case 0:
1113
1113
  mpfr_set_default_rounding_mode (GMP_RNDN); break;
@@ -1122,17 +1122,17 @@ VALUE r_gmpfsg_set_default_rounding_mode(VALUE klass, VALUE arg)
1122
1122
  mpfr_set_default_rounding_mode (MPFR_RNDA); break;
1123
1123
  #endif
1124
1124
  }
1125
-
1125
+
1126
1126
  return Qnil;
1127
1127
  }
1128
-
1128
+
1129
1129
  VALUE r_gmpf_can_round(VALUE self, VALUE err, VALUE rnd1, VALUE rnd2, VALUE prec)
1130
1130
  {
1131
1131
  MP_FLOAT *self_val;
1132
1132
  mp_exp_t err_val;
1133
1133
  mpfr_rnd_t rnd1_val, rnd2_val;
1134
1134
  mpfr_prec_t prec_val;
1135
-
1135
+
1136
1136
  mpf_get_struct(self, self_val);
1137
1137
  if (FIXNUM_P(err)) {
1138
1138
  err_val = FIX2INT(err);
@@ -1142,7 +1142,7 @@ VALUE r_gmpf_can_round(VALUE self, VALUE err, VALUE rnd1, VALUE rnd2, VALUE prec
1142
1142
  rnd1_val = r_get_rounding_mode(rnd1);
1143
1143
  rnd2_val = r_get_rounding_mode(rnd2);
1144
1144
  prec_val = FIX2INT (prec);
1145
-
1145
+
1146
1146
  if (mpfr_can_round (self_val, err_val, rnd1_val, rnd2_val, prec_val))
1147
1147
  return Qtrue;
1148
1148
  else
@@ -1152,6 +1152,23 @@ VALUE r_gmpf_can_round(VALUE self, VALUE err, VALUE rnd1, VALUE rnd2, VALUE prec
1152
1152
  #endif
1153
1153
 
1154
1154
 
1155
+ /**********************************************************************
1156
+ * Rounding Related Functions *
1157
+ **********************************************************************/
1158
+
1159
+ VALUE r_gmpfsg_mpfr_buildopt_tls_p(VALUE klass)
1160
+ {
1161
+ (void)klass;
1162
+ return INT2FIX (mpfr_buildopt_tls_p());
1163
+ }
1164
+
1165
+ VALUE r_gmpfsg_mpfr_buildopt_decimal_p(VALUE klass)
1166
+ {
1167
+ (void)klass;
1168
+ return INT2FIX (mpfr_buildopt_decimal_p());
1169
+ }
1170
+
1171
+
1155
1172
  /**********************************************************************
1156
1173
  * _unsorted_ *
1157
1174
  **********************************************************************/
@@ -1192,22 +1209,22 @@ void init_gmpf()
1192
1209
  {
1193
1210
  mGMP = rb_define_module("GMP");
1194
1211
  rb_define_module_function(mGMP, "F", r_gmpmod_f, -1);
1195
-
1212
+
1196
1213
  cGMP_F = rb_define_class_under (mGMP, "F", rb_cNumeric);
1197
-
1198
-
1214
+
1215
+
1199
1216
  // Initializing, Assigning Floats
1200
1217
  rb_define_singleton_method(cGMP_F, "new", r_gmpfsg_new, -1);
1201
1218
  rb_define_method(cGMP_F, "initialize", r_gmpf_initialize, -1);
1202
1219
  rb_define_method(cGMP_F, "prec", r_gmpf_get_prec, 0);
1203
1220
  rb_define_method(cGMP_F, "prec=", r_gmpf_set_prec, 1);
1204
1221
  rb_define_method(cGMP_F, "prec_raw=", r_gmpf_set_prec_raw, 1);
1205
-
1222
+
1206
1223
  // Converting Floats
1207
1224
  rb_define_method(cGMP_F, "to_s", r_gmpf_to_s, 0);
1208
1225
  rb_define_method(cGMP_F, "to_d", r_gmpf_to_d, 0);
1209
1226
  rb_define_alias(cGMP_F, "to_f", "to_d");
1210
-
1227
+
1211
1228
  // Float Arithmetic
1212
1229
  rb_define_method(cGMP_F, "-", r_gmpf_sub, 1);
1213
1230
  rb_define_method(cGMP_F, "/", r_gmpf_div, 1);
@@ -1226,7 +1243,7 @@ void init_gmpf()
1226
1243
  rb_define_method(cGMP_F, "neg!", r_gmpf_neg_self, 0);
1227
1244
  rb_define_method(cGMP_F, "abs", r_gmpf_abs, 0);
1228
1245
  rb_define_method(cGMP_F, "abs!", r_gmpf_abs_self, 0);
1229
-
1246
+
1230
1247
  // Float Comparison
1231
1248
  rb_define_method(cGMP_F, "<=>", r_gmpf_cmp, 1);
1232
1249
  rb_define_method(cGMP_F, ">", r_gmpf_cmp_gt, 1);
@@ -1235,20 +1252,18 @@ void init_gmpf()
1235
1252
  rb_define_method(cGMP_F, "<=", r_gmpf_cmp_le, 1);
1236
1253
  rb_define_method(cGMP_F, "==", r_gmpf_eq, 1);
1237
1254
  rb_define_method(cGMP_F, "sgn", r_gmpf_sgn, 0);
1238
-
1255
+
1239
1256
  // Miscellaneous Functions
1240
1257
  rb_define_method(cGMP_F, "ceil", r_gmpf_ceil, 0);
1241
1258
  rb_define_method(cGMP_F, "ceil!", r_gmpf_ceil_self, 0);
1242
1259
  rb_define_method(cGMP_F, "floor", r_gmpf_floor, 0);
1243
1260
  rb_define_method(cGMP_F, "floor!", r_gmpf_floor_self, 0);rb_define_method(cGMP_F, "trunc", r_gmpf_trunc, 0);
1244
1261
  rb_define_method(cGMP_F, "trunc!", r_gmpf_trunc_self, 0);
1245
-
1246
-
1262
+
1263
+
1247
1264
  #ifdef MPFR
1248
1265
  /* To implement; new in MPFR 3.0.0:
1249
1266
  *
1250
- * mpfr_buildopt_tls_p
1251
- * mpfr_buildopt_decimal_p
1252
1267
  * mpfr_set_zero
1253
1268
  * mpfr_ai
1254
1269
  * mpfr_set_flt
@@ -1256,6 +1271,16 @@ void init_gmpf()
1256
1271
  * mpfr_urandom
1257
1272
  * mpfr_set_z_2exp
1258
1273
  */
1274
+
1275
+ /* To implement; new in MPFR 3.1.0:
1276
+ *
1277
+ * mpfr_buildopt_gmpinternals_p
1278
+ * mpfr_buildopt_tune_case
1279
+ * mpfr_frexp
1280
+ * mpfr_grandom
1281
+ * mpfr_z_sub
1282
+ */
1283
+
1259
1284
  // Basic Arithmetic Functions
1260
1285
  rb_define_method(cGMP_F, "sqrt", r_gmpfr_sqrt, -1);
1261
1286
  rb_define_method(cGMP_F, "rec_sqrt", r_gmpfr_rec_sqrt, -1);
@@ -1266,9 +1291,9 @@ void init_gmpf()
1266
1291
  // "dim", r_gmpfr_dim
1267
1292
  // "mul_2", r_gmpfr_mul_2
1268
1293
  // "div_2", r_gmpfr_div_2
1269
-
1294
+
1270
1295
  //rb_define_method(cGMP_F, "**", r_gmpfr_pow, 1);
1271
-
1296
+
1272
1297
  // Comparison Functions
1273
1298
  rb_define_method(cGMP_F, "nan?", r_gmpfr_nan_p, 0);
1274
1299
  rb_define_method(cGMP_F, "infinite?", r_gmpfr_inf_p, 0);
@@ -1281,7 +1306,7 @@ void init_gmpf()
1281
1306
  //"sgn", r_gmpfr_sgn
1282
1307
  //"lessgreater", r_gmpfr_lessgreater_p
1283
1308
  //"unordered", r_gmpfr_unordered_p
1284
-
1309
+
1285
1310
  // Special Functions
1286
1311
  rb_define_method(cGMP_F, "log", r_gmpfr_log, -1);
1287
1312
  rb_define_method(cGMP_F, "log2", r_gmpfr_log2, -1);
@@ -1310,7 +1335,7 @@ void init_gmpf()
1310
1335
  rb_define_method(cGMP_F, "acosh", r_gmpfr_acosh, -1);
1311
1336
  rb_define_method(cGMP_F, "asinh", r_gmpfr_asinh, -1);
1312
1337
  rb_define_method(cGMP_F, "atanh", r_gmpfr_atanh, -1);
1313
-
1338
+
1314
1339
  // "fac", r_gmpfr_fac
1315
1340
 
1316
1341
  rb_define_method(cGMP_F, "log1p", r_gmpfr_log1p, -1);
@@ -1338,7 +1363,7 @@ void init_gmpf()
1338
1363
  rb_define_method(cGMP_F, "agm", r_gmpfr_agm, -1);
1339
1364
  rb_define_method(cGMP_F, "hypot", r_gmpfr_hypot, -1);
1340
1365
  // "ai", r_gmpfr_ai !! 3.0.0
1341
-
1366
+
1342
1367
  rb_define_singleton_method(cGMP_F, "const_log2", r_gmpfrsg_const_log2, -1);
1343
1368
  rb_define_singleton_method(cGMP_F, "const_pi", r_gmpfrsg_const_pi, -1);
1344
1369
  rb_define_singleton_method(cGMP_F, "const_euler", r_gmpfrsg_const_euler, -1);
@@ -1346,12 +1371,18 @@ void init_gmpf()
1346
1371
 
1347
1372
  // Integer and Remainder Related Functions
1348
1373
  // "integer?", r_gmpfr_integer_p
1349
-
1374
+
1350
1375
  // Rounding Related Functions
1351
1376
  rb_define_singleton_method (cGMP_F, "default_rounding_mode", r_gmpfsg_get_default_rounding_mode, 0);
1352
1377
  rb_define_singleton_method (cGMP_F, "default_rounding_mode=", r_gmpfsg_set_default_rounding_mode, 1);
1353
1378
  rb_define_method(cGMP_F, "can_round?", r_gmpf_can_round, 4);
1379
+
1380
+ // Miscellaneous Functions
1381
+ #if MPFR_VERSION_MAJOR > 2
1382
+ rb_define_singleton_method (cGMP_F, "mpfr_buildopt_decimal_p", r_gmpfsg_mpfr_buildopt_decimal_p, 0);
1383
+ rb_define_singleton_method (cGMP_F, "mpfr_buildopt_tls_p", r_gmpfsg_mpfr_buildopt_tls_p, 0);
1384
+ #endif /* MPFR > 2 */
1354
1385
  #endif /* MPFR */
1355
-
1386
+
1356
1387
  // _unsorted_
1357
1388
  }
data/ext/gmpq.c CHANGED
@@ -69,6 +69,7 @@ static VALUE r_gmpq_##fname##_self(VALUE self) \
69
69
  /*
70
70
  * call-seq:
71
71
  * GMP::Q.new(arg)
72
+ * GMP::Q.new(num,den)
72
73
  *
73
74
  * Creates a new GMP::Q rational, with _arg_ as its value, converting where
74
75
  * necessary.
@@ -86,10 +87,52 @@ VALUE r_gmpqsg_new(int argc, VALUE *argv, VALUE klass)
86
87
  mpq_make_struct (res, res_val);
87
88
  mpq_init (res_val);
88
89
  rb_obj_call_init(res, argc, argv);
89
-
90
+
90
91
  return res;
91
92
  }
92
93
 
94
+ static void mpq_str_set(MP_RAT *ROP, char *str)
95
+ {
96
+ int i=0;
97
+
98
+ while (str[i] && str[i] != '/')
99
+ i++;
100
+
101
+ if (str[i])
102
+ {
103
+ str[i] = 0; /* You didn't see that :) */
104
+ mpz_set_str (mpq_numref(ROP), str, 0);
105
+ str[i] = '/';
106
+ mpz_set_str (mpq_denref(ROP), str+i+1, 0);
107
+ } else {
108
+ mpz_set_str (mpq_numref(ROP), str, 0);
109
+ mpz_set_ui (mpq_denref(ROP), 1);
110
+ }
111
+ mpq_canonicalize (ROP);
112
+ }
113
+
114
+ VALUE r_gmpq_initialize(int argc, VALUE *argv, VALUE self)
115
+ {
116
+ MP_RAT *self_val, *arg_val;
117
+
118
+ if (argc != 0) {
119
+ mpq_get_struct(self, self_val);
120
+ if (argc == 1 && GMPQ_P(argv[0])) {
121
+ mpq_get_struct(argv[0], arg_val);
122
+ mpq_set (self_val, arg_val);
123
+ } else if (argc == 1 && STRING_P(argv[0])) {
124
+ mpq_str_set (self_val, StringValuePtr(argv[0]));
125
+ } else {
126
+ mpz_set_value (mpq_numref(self_val), argv[0], 0); // are these segfaulting?
127
+ if (argc == 2) {
128
+ mpz_set_value (mpq_denref(self_val), argv[1], 0); // are these segfaulting?
129
+ mpq_canonicalize(self_val);
130
+ } // AND IF ARGC != 2 ?!? WHAT JUST HAPPENED?
131
+ }
132
+ }
133
+ return Qnil;
134
+ }
135
+
93
136
  /*
94
137
  * call-seq:
95
138
  * GMP::Q(arg)
@@ -686,6 +729,47 @@ VALUE r_gmpq_sgn(VALUE self)
686
729
  return INT2FIX(mpq_sgn(self_val));
687
730
  }
688
731
 
732
+ /*
733
+ * call-seq:
734
+ * a.eql?(b)
735
+ *
736
+ * @since 0.5.47
737
+ *
738
+ * Returns true if _a_ is equal to _b_. _a_ and _b_ must then be equal in cardinality,
739
+ * and both be instances of GMP::Q. Otherwise, returns false. a.eql?(b) if and only if
740
+ * b.class == GMP::Q, and a.hash == b.hash.
741
+ */
742
+ VALUE r_gmpq_eql(VALUE self, VALUE arg)
743
+ {
744
+ MP_RAT *self_val, *arg_val;
745
+ mpq_get_struct(self,self_val);
746
+
747
+ if (GMPQ_P(arg)) {
748
+ mpq_get_struct(arg, arg_val);
749
+ return (mpq_cmp (self_val, arg_val) == 0) ? Qtrue : Qfalse;
750
+ }
751
+ else {
752
+ return Qfalse;
753
+ }
754
+ }
755
+
756
+ /*
757
+ * call-seq:
758
+ * a.hash
759
+ *
760
+ * @since 0.5.47
761
+ *
762
+ * Returns the computed hash value of _a_. This method first converts _a_ into a String
763
+ * (base 10), then calls String#hash on the result, returning the hash value. a.eql?(b)
764
+ * if and only if b.class == GMP::Q, and a.hash == b.hash.
765
+ */
766
+ VALUE r_gmpq_hash(VALUE self)
767
+ {
768
+ ID to_s_sym = rb_intern("to_s");
769
+ ID hash_sym = rb_intern("hash");
770
+ return rb_funcall(rb_funcall(self, to_s_sym, 0), hash_sym, 0);
771
+ }
772
+
689
773
  /**********************************************************************
690
774
  * Applying Integer Functions *
691
775
  **********************************************************************/
@@ -752,6 +836,9 @@ void init_gmpq()
752
836
  rb_define_method(cGMP_Q, "sgn", r_gmpq_sgn, 0);
753
837
  rb_define_method(cGMP_Q, "cmpabs", r_gmpq_cmpabs, 1);
754
838
 
839
+ rb_define_method(cGMP_Q, "eql?", r_gmpq_eql, 1);
840
+ rb_define_method(cGMP_Q, "hash", r_gmpq_hash, 0);
841
+
755
842
  // _unsorted_
756
843
  rb_define_method(cGMP_Q, "floor", r_gmpq_floor, 0);
757
844
  rb_define_method(cGMP_Q, "ceil", r_gmpq_ceil, 0);