e576bb2002-10-11Martin Nilsson /* -*- c -*- || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */
08d6302002-10-10Martin Nilsson 
d4bf622001-08-13Fredrik Hübinette (Hubbe) #include "global.h" #include "gmp_machine.h"
2b1c922013-12-24Henrik Grubbström (Grubba) #include "my_gmp.h"
d4bf622001-08-13Fredrik Hübinette (Hubbe) #include "interpret.h" #include "svalue.h" #include "stralloc.h" #include "array.h" #include "pike_macros.h" #include "program.h" #include "object.h" #include "pike_types.h" #include "pike_error.h" #include "builtin_functions.h" #include "module_support.h" #include "bignum.h" #include "operators.h" #include "mapping.h"
ad8d052008-05-02Martin Stjernholm #include "gc.h"
d4bf622001-08-13Fredrik Hübinette (Hubbe)  #include <math.h>
2505872002-09-25Marcus Comstedt 
531c172002-05-11Martin Nilsson #define sp Pike_sp #define fp Pike_fp
f91e682014-09-10Tobias S. Josefowitz #define DEFAULT_CMOD_STORAGE
56c0642008-07-31Martin Stjernholm DECLARATIONS
d4bf622001-08-13Fredrik Hübinette (Hubbe) #define THISMPQ (&(THIS->n))
8388f92003-09-01Martin Nilsson /*! @module Gmp */ /*! @class mpq
25616a2004-03-23Martin Nilsson  *! Rational number stored in canonical form. The canonical from means *! that the denominator and the numerator have no common factors, and *! that the denominator is positive. Zero has the unique *! representation 0/1. All functions canonicalize their result.
8388f92003-09-01Martin Nilsson  */
d4bf622001-08-13Fredrik Hübinette (Hubbe) /* id PROG_GMP_MPQ_ID; */ PIKECLASS mpq { CVAR MP_RAT n; static void get_mpq_from_digits(MP_RAT *tmp, struct pike_string *digits, int base)
486f872016-06-08Per Hedbor  { p_wchar0 *str;
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  if(digits->size_shift) Pike_error("Illegal characters, cannot convert to mpq.\n"); str=STR0(digits);
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  /* Huh, wot? /mast get_mpz_from_digits(mpq_numref(tmp), digits, base); */
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  if(!base || ((base >= 2) && (base <= 36))) { int offset = 0; int neg = 0; int dotfound = 0;
d4bf622001-08-13Fredrik Hübinette (Hubbe) 
486f872016-06-08Per Hedbor  if(digits->len > 1)
d4bf622001-08-13Fredrik Hübinette (Hubbe)  {
486f872016-06-08Per Hedbor  if(str[0] == '+') offset ++; else if(str[0] == '-') { offset ++; neg = 1; } /* We need to fix the case with binary 0b101... and -0b101... numbers. */ if(!base && digits->len > 2) { if(str[offset] == '0') { switch(str[offset+1]) { case 'b': case 'B': offset+=2; base=2; break; case '0': offset+=2; base=8; break; case 'x': offset+=2; base=16; break; } } }
d4bf622001-08-13Fredrik Hübinette (Hubbe)  }
486f872016-06-08Per Hedbor  if(!base) base=10; mpq_set_ui(tmp, 0, 1); while(str[offset])
d4bf622001-08-13Fredrik Hübinette (Hubbe)  {
486f872016-06-08Per Hedbor  int x=255; if(str[offset] == '.') { offset++; if(dotfound) Pike_error("Invalid digits, cannot convert to mpq.\n"); dotfound++; continue; } if(str[offset] >= '0' && str[offset] <= '9') x=str[offset]-'0'; else if(str[offset] >='a' && str[offset] <= 'z') x=str[offset]-'a'; else if(str[offset] >='A' && str[offset] <= 'Z') x=str[offset]-'A'; if(x > base) Pike_error("Invalid digits, cannot convert to mpq.\n"); mpz_mul_ui(mpq_numref(tmp), mpq_numref(tmp), base); if(dotfound) { mpz_mul_ui(mpq_denref(tmp), mpq_denref(tmp), base); } mpz_add_ui(mpq_numref(tmp), mpq_numref(tmp), x); offset++;
d4bf622001-08-13Fredrik Hübinette (Hubbe)  }
486f872016-06-08Per Hedbor  if(dotfound) mpq_canonicalize(tmp); if(neg) mpz_neg(mpq_numref(tmp), mpq_numref(tmp));
d4bf622001-08-13Fredrik Hübinette (Hubbe)  }
486f872016-06-08Per Hedbor  else if(base == 256) { mpq_set_ui(tmp, 1, 1); get_mpz_from_digits(mpq_numref(tmp), digits, base); } else { Pike_error("invalid base.\n"); } }
d4bf622001-08-13Fredrik Hübinette (Hubbe) 
afcf782003-03-28Martin Stjernholm  int get_new_mpq(MP_RAT *tmp, struct svalue *s, int throw_error, const char *arg_func, int arg, int args)
486f872016-06-08Per Hedbor  { switch(TYPEOF(*s))
d4bf622001-08-13Fredrik Hübinette (Hubbe)  {
486f872016-06-08Per Hedbor  case T_FLOAT:
d4bf622001-08-13Fredrik Hübinette (Hubbe)  { double t; int y;
d0ffd92014-09-03Martin Nilsson  t=frexp((double) s->u.float_number, &y);
d4bf622001-08-13Fredrik Hübinette (Hubbe)  t*=pow(2.0,48.0); y-=48; mpz_set_d(mpq_numref(tmp), t); mpz_set_ui(mpq_denref(tmp), 1); if(y>0) mpz_mul_2exp(mpq_numref(tmp),mpq_numref(tmp),y); else if(y<0) mpz_mul_2exp(mpq_denref(tmp),mpq_denref(tmp),-y); mpq_canonicalize(tmp); break; }
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  case T_INT: get_new_mpz(mpq_numref(tmp), s, 1, arg_func, arg, args); mpz_set_si(mpq_denref(tmp),1); break; case T_OBJECT: if(IS_MPZ_OBJ (s->u.object)) { mpq_set_z(tmp, OBTOMPZ(s->u.object)); break; } if(s->u.object->prog == mpq_program) { mpq_set(tmp, OBTOMPQ(s->u.object)); break; } if(s->u.object->prog == mpf_program) {
c6e4eb2016-06-09Per Hedbor  MP_INT z;
486f872016-06-08Per Hedbor  long exponent;
2452562016-07-08Henrik Grubbström (Grubba) #ifndef USE_MPFR
c6e4eb2016-06-09Per Hedbor  // Acces mpf internals directly. // NOTE: Hacky! Must not free z "correctly" exponent = OBTOMPF(s->u.object)->_mp_exp*sizeof(mp_limb_t)*8;
2452562016-07-08Henrik Grubbström (Grubba)  z._mp_size = OBTOMPF(s->u.object)->_mp_size;
486f872016-06-08Per Hedbor  z._mp_d = OBTOMPF(s->u.object)->_mp_d;
2452562016-07-08Henrik Grubbström (Grubba)  /* NB: For simplicity we assume that we won't have values with more * than GMP_NUMB_BITS * 0x7ffffff (typically 8 or 16 GB) bits. * * Further: As we don't perform any destructive operations on * the z below, the field will probably not be used. */ z._mp_alloc = abs((INT32)z._mp_size);
c6e4eb2016-06-09Per Hedbor #else
8d0b8c2016-06-09Per Hedbor  mpz_init(&z);
c6e4eb2016-06-09Per Hedbor  exponent = mpfr_get_z_2exp(&z, OBTOMPF(s->u.object) ); #endif
486f872016-06-08Per Hedbor  mpz_set( mpq_numref(tmp), &z); mpz_set_ui(mpq_denref(tmp),1);
c6e4eb2016-06-09Per Hedbor  if( exponent < 0 ) mpz_mul_2exp(mpq_denref(tmp),mpq_denref(tmp),-exponent); else if( exponent > 0 ) mpz_mul_2exp(mpq_numref(tmp),mpq_numref(tmp),exponent);
486f872016-06-08Per Hedbor  mpq_canonicalize(tmp);
8d0b8c2016-06-09Per Hedbor 
2452562016-07-08Henrik Grubbström (Grubba) #ifdef USE_MPFR
8d0b8c2016-06-09Per Hedbor  mpz_clear(&z); #endif
486f872016-06-08Per Hedbor  break; }
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  if (s->u.object->prog) { if (throw_error) SIMPLE_ARG_TYPE_ERROR (arg_func, arg, "int|float|Gmp.mpq|Gmp.mpz|Gmp.mpf"); else return 0; } else { /* Destructed object. Use as zero. */ mpq_set_si(tmp, 0, 1); } break;
afcf782003-03-28Martin Stjernholm 
486f872016-06-08Per Hedbor  default: if (throw_error) SIMPLE_ARG_TYPE_ERROR (arg_func, arg, "int|float|Gmp.mpq|Gmp.mpz|Gmp.mpf"); else return 0;
d4bf622001-08-13Fredrik Hübinette (Hubbe)  }
486f872016-06-08Per Hedbor  return 1; }
afcf782003-03-28Martin Stjernholm  /* Converts an svalue, located on the stack, to an mpq object */ static MP_RAT *debug_get_mpq(struct svalue *s, int throw_error, const char *arg_func, int arg, int args) { struct object *o = fast_clone_object (mpq_program); ONERROR uwp; SET_ONERROR (uwp, do_free_object, o); if (get_new_mpq (OBTOMPQ (o), s, throw_error, arg_func, arg, args)) { UNSET_ONERROR (uwp); free_svalue(s);
017b572011-10-28Henrik Grubbström (Grubba)  SET_SVAL(*s, T_OBJECT, 0, object, o);
afcf782003-03-28Martin Stjernholm  return OBTOMPQ (o); } else { UNSET_ONERROR (uwp);
aaaab72003-03-29Martin Stjernholm  free_object (o);
afcf782003-03-28Martin Stjernholm  return NULL; } } #ifdef DEBUG_MALLOC #define get_mpq(S, THROW_ERROR, ARG_FUNC, ARG, ARGS) \
4a93e82013-06-11Henrik Grubbström (Grubba)  (REFCOUNTED_TYPE(TYPEOF(*(S))) ? debug_malloc_touch((S)->u.object) : 0, \
afcf782003-03-28Martin Stjernholm  debug_get_mpq((S), (THROW_ERROR), (ARG_FUNC), (ARG), (ARGS))) #else #define get_mpq debug_get_mpq #endif
7050b62016-06-03Per Hedbor  PIKEFUN float|mpq|int ``**(int|float exponent) {
4823282016-11-05Henrik Grubbström (Grubba)  double x;
486f872016-06-08Per Hedbor  /* does not support expoent being object, `** should have been used in that case. */
7050b62016-06-03Per Hedbor  if( TYPEOF(*exponent) == PIKE_T_FLOAT ) { if( (double)(long)exponent->u.float_number == exponent->u.float_number ) { TYPEOF(*exponent)=PIKE_T_INT; exponent->u.integer = (long)exponent->u.float_number; } } if( TYPEOF(*exponent) == PIKE_T_INT ) { // int ** mpq counted as int ** float not int ** int. // promote to mpq or float. get_mpq( Pike_sp-1, 1, "``**", 1, 1 ); ref_push_object( Pike_fp->current_object ); apply_lfun( Pike_sp[-2].u.object, LFUN_POW, 1 ); return; }
4823282016-11-05Henrik Grubbström (Grubba)  x = mpq_get_d(THISMPQ);
486f872016-06-08Per Hedbor  Pike_sp[-1].u.float_number = pow( Pike_sp[-1].u.float_number, x);
7050b62016-06-03Per Hedbor  }
486f872016-06-08Per Hedbor  PIKEFUN mpq `**(int exponent)
7050b62016-06-03Per Hedbor  {
486f872016-06-08Per Hedbor  struct object *o = fast_clone_object( mpq_program ); push_object(o); if( exponent >= 0 )
7050b62016-06-03Per Hedbor  {
486f872016-06-08Per Hedbor  mpz_pow_ui( mpq_numref(OBTOMPQ(o)), mpq_numref(THISMPQ), exponent ); mpz_pow_ui( mpq_denref(OBTOMPQ(o)), mpq_denref(THISMPQ), exponent );
7050b62016-06-03Per Hedbor  } else {
486f872016-06-08Per Hedbor  mpz_pow_ui( mpq_numref(OBTOMPQ(o)), mpq_denref(THISMPQ), -exponent ); mpz_pow_ui( mpq_denref(OBTOMPQ(o)), mpq_numref(THISMPQ), -exponent );
7050b62016-06-03Per Hedbor  }
486f872016-06-08Per Hedbor  mpq_canonicalize(OBTOMPQ(o));
7050b62016-06-03Per Hedbor  }
486f872016-06-08Per Hedbor  PIKEFUN float|mpq `**(float exponent)
7050b62016-06-03Per Hedbor  {
4823282016-11-05Henrik Grubbström (Grubba)  double x;
486f872016-06-08Per Hedbor  if( (double)(int)exponent == exponent ) { Pike_sp[-1].u.integer = (INT_TYPE)Pike_sp[-1].u.float_number; TYPEOF(Pike_sp[-1]) = PIKE_T_INT; f_mpq_cq__backtick_2A_2A_1(1); return; }
4823282016-11-05Henrik Grubbström (Grubba)  x = mpq_get_d(THISMPQ);
486f872016-06-08Per Hedbor  x = pow(x, exponent); if( (double)(long)x == x ) { struct object *o = fast_clone_object( mpq_program ); push_object(o); mpq_set_si( OBTOMPQ(o), (long)x, 1 ); } else { push_float( x ); } }
7050b62016-06-03Per Hedbor 
486f872016-06-08Per Hedbor  PIKEFUN mpq `**(object _exponent) { signed long tmpi; MP_INT tmp; struct object *o; MP_RAT *exponent; mpz_init( &tmp ); if(_exponent->prog != mpq_program) { _exponent = fast_clone_object(mpq_program); get_new_mpq(OBTOMPQ(_exponent), Pike_sp-1, 1, "`**", 1, 1); } exponent = OBTOMPQ(_exponent); // x ^ (exponent/divisor) tmpi = mpz_get_si(mpq_numref(exponent)); if( !mpz_fits_slong_p(mpq_numref(exponent)) || !mpz_fits_slong_p(mpq_denref(exponent)) || labs(tmpi)* MAXIMUM(mpz_size(mpq_numref(exponent)), mpz_size(mpq_denref(exponent))) > (0x40000000/sizeof(mp_limb_t))) { // Well, bother that (more than 1Gb temporary). // Fall back to float version. goto float_fallback; } push_int( tmpi ); f_mpq_cq__backtick_2A_2A_1(1); // now in o (and on stack): Exponented number. o = Pike_sp[-1].u.object; // now do x:th root part. tmpi = mpz_get_si(mpq_denref(exponent)); if( tmpi != 1 ) { mpz_rootrem(mpq_numref(OBTOMPQ(o)),&tmp,mpq_numref(OBTOMPQ(o)),tmpi); if( mpz_sgn( &tmp ) ) goto float_fallback; mpz_rootrem(mpq_denref(OBTOMPQ(o)),&tmp,mpq_denref(OBTOMPQ(o)),tmpi); if( mpz_sgn( &tmp ) ) goto float_fallback; /* o already on stack, all done. */ mpz_clear(&tmp); mpq_canonicalize(OBTOMPQ(o)); } return; float_fallback: // the result can not be represented exactly, or is just too huge. push_float( pow(mpq_get_d(THISMPQ),mpq_get_d(exponent)) );
7050b62016-06-03Per Hedbor  }
7cfb2e2014-10-01Per Hedbor  /*! @decl protected void create(void|string|int|float|Gmp.mpz|Gmp.mpq x)
ac21762016-06-04Henrik Grubbström (Grubba)  *! @decl protected void create(int|Gmp.mpz numerator, @ *! int|Gmp.mpz denominator)
7cfb2e2014-10-01Per Hedbor  *! @decl protected void create(string x, int base)
8388f92003-09-01Martin Nilsson  */
ac21762016-06-04Henrik Grubbström (Grubba)  PIKEFUN void create(void|string|int|float|object x, void|int|object base)
d4bf622001-08-13Fredrik Hübinette (Hubbe)  type function(void|string|int|float|object:void)|function(string,int:void)|function(int,int:void);
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
d4bf622001-08-13Fredrik Hübinette (Hubbe)  { switch(args) { case 2: /* Args are string of digits and integer base */ /* or int num / den */
72bc912014-02-25Per Hedbor 
b753a12015-04-17Henrik Grubbström (Grubba)  if (base && x) {
d4bf622001-08-13Fredrik Hübinette (Hubbe) 
b753a12015-04-17Henrik Grubbström (Grubba)  switch(TYPEOF(*x)) {
d4bf622001-08-13Fredrik Hübinette (Hubbe)  case T_STRING:
ac21762016-06-04Henrik Grubbström (Grubba)  if (TYPEOF(*base) != T_INT) SIMPLE_ARG_TYPE_ERROR ("create", 2, "int");
72bc912014-02-25Per Hedbor  get_mpq_from_digits(THISMPQ, x->u.string, base->u.integer);
d4bf622001-08-13Fredrik Hübinette (Hubbe)  break;
3bb5862015-04-25Henrik Grubbström (Grubba)  default: SIMPLE_ARG_TYPE_ERROR ("create", 1, "int|string"); break;
42571a2005-09-14Marcus Comstedt  case T_OBJECT:
ac21762016-06-04Henrik Grubbström (Grubba)  if(x->u.object->prog != bignum_program && x->u.object->prog != mpzmod_program)
de22f72014-08-25Martin Nilsson  SIMPLE_ARG_TYPE_ERROR ("create", 1, "int|string");
42571a2005-09-14Marcus Comstedt 
5f50842018-02-12Marcus Comstedt  /* FALLTHRU */
3bb5862015-04-25Henrik Grubbström (Grubba) 
d4bf622001-08-13Fredrik Hübinette (Hubbe)  case T_INT:
ac21762016-06-04Henrik Grubbström (Grubba)  if (TYPEOF(*base) != T_INT && !(TYPEOF(*base) == T_OBJECT && (base->u.object->prog == bignum_program || base->u.object->prog == mpzmod_program))) SIMPLE_ARG_TYPE_ERROR ("create", 2, "int");
de22f72014-08-25Martin Nilsson  mpq_set_num(THISMPQ,get_mpz(x, 1, "create", 1, args)); mpq_set_den(THISMPQ,get_mpz(base, 1, "create", 2, args));
d4bf622001-08-13Fredrik Hübinette (Hubbe)  mpq_canonicalize(THISMPQ); break;
b753a12015-04-17Henrik Grubbström (Grubba)  } break; }
5f50842018-02-12Marcus Comstedt  /* FALLTHRU */
b753a12015-04-17Henrik Grubbström (Grubba)  case 1: if (x) { if(TYPEOF(*x) == T_STRING) get_mpq_from_digits(THISMPQ, x->u.string, 0); else get_new_mpq(THISMPQ, x, 1, "create", 1, args); break;
d4bf622001-08-13Fredrik Hübinette (Hubbe)  }
5f50842018-02-12Marcus Comstedt  /* FALLTHRU */
b753a12015-04-17Henrik Grubbström (Grubba)  case 0:
d4bf622001-08-13Fredrik Hübinette (Hubbe)  break;
72bc912014-02-25Per Hedbor 
d4bf622001-08-13Fredrik Hübinette (Hubbe)  default:
de22f72014-08-25Martin Nilsson  SIMPLE_WRONG_NUM_ARGS_ERROR ("create", 2);
d4bf622001-08-13Fredrik Hübinette (Hubbe)  }
b498ad2017-12-28Martin Nilsson  pop_n_elems(args);
d4bf622001-08-13Fredrik Hübinette (Hubbe)  }
72bc912014-02-25Per Hedbor 
8388f92003-09-01Martin Nilsson  /*! @decl int get_int() */
d4bf622001-08-13Fredrik Hübinette (Hubbe)  PIKEFUN int get_int()
486f872016-06-08Per Hedbor  { struct object *res = fast_clone_object(mpzmod_program); mpz_tdiv_q(OBTOMPZ(res), mpq_numref(THISMPQ), mpq_denref(THISMPQ)); /* FIXME */ mpzmod_reduce(res); }
d4bf622001-08-13Fredrik Hübinette (Hubbe) 
7cfb2e2014-10-01Per Hedbor  /*! @decl protected int __hash()
8388f92003-09-01Martin Nilsson  */
d4bf622001-08-13Fredrik Hübinette (Hubbe)  PIKEFUN int __hash()
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
486f872016-06-08Per Hedbor  { RETURN mpz_get_si(mpq_numref(THISMPQ)) * 1000003 + mpz_get_si(mpq_denref(THISMPQ)); }
d4bf622001-08-13Fredrik Hübinette (Hubbe) 
8388f92003-09-01Martin Nilsson  /*! @decl float get_float() */
d4bf622001-08-13Fredrik Hübinette (Hubbe)  PIKEFUN float get_float()
486f872016-06-08Per Hedbor  { RETURN (FLOAT_TYPE) mpq_get_d(THISMPQ); }
d4bf622001-08-13Fredrik Hübinette (Hubbe) 
f22ec82011-03-08Martin Stjernholm  static void format_dec_frac (mpz_t num, int prec)
137a3e2011-03-05Martin Stjernholm  { struct pike_string *s;
f22ec82011-03-08Martin Stjernholm  ptrdiff_t len = mpz_sizeinbase (num, 10); assert (prec); if (len > prec) { /* one for the dot... */ prec++; /* present 'num' and insert dot */ len += 3;
9025ed2018-05-30Stephen R. van den Berg  s = begin_shared_string(len + 1); /* +1 to cater for a leading 0 */
f22ec82011-03-08Martin Stjernholm  if(len/2 > prec) { /* Shift the integer part forward to make room for the dot. */ mpz_get_str(s->str+1, 10, num); /* Find NULL character */ len-=4; if (len < 1) len = 1; while(s->str[len]) len++;
68c0a82014-09-03Martin Nilsson  memmove(s->str, s->str+1, len-prec);
f22ec82011-03-08Martin Stjernholm  }else{ /* Shift the fractional part backward to make room for the dot. */ mpz_get_str(s->str, 10, num); /* Find NULL character */ len-=5; if (len < 0) len = 0; while(s->str[len]) len++;
68c0a82014-09-03Martin Nilsson  memmove(s->str+len-prec+1,
f22ec82011-03-08Martin Stjernholm  s->str+len-prec, prec+1); len++; }
6bb0162018-05-30Stephen R. van den Berg  /* Make sure numbers start with a digit */ if ((len == prec) || ((unsigned)(s->str[len-prec-1] - '0') > 9)) { memmove(s->str+len-prec+1, s->str+len-prec, prec); s->str[len++ -prec] = '0';
9025ed2018-05-30Stephen R. van den Berg  }
6bb0162018-05-30Stephen R. van den Berg  s->str[len-prec]='.';
f22ec82011-03-08Martin Stjernholm  push_string (end_and_resize_shared_string (s, len)); } else { /* The precision is greater than the length, so start out * with a string of zeroes. */ char *p; s = begin_shared_string (prec + 4); p = s->str; if (mpz_sgn (num) < 0) { *p++ = '-'; mpz_neg (num, num); } *p++ = '0'; *p++ = '.'; for (; prec > len; prec--) *p++ = '0'; mpz_get_str (p, 10, num); if (!p[len - 1]) {
68c0a82014-09-03Martin Nilsson  memmove (p + 1, p, len - 1);
f22ec82011-03-08Martin Stjernholm  *p = '0'; } push_string (end_and_resize_shared_string (s, p - s->str + len));
137a3e2011-03-05Martin Stjernholm  } } static void format_string (mpq_t mpq, int dec_fract) { if (dec_fract >= 1) {
82ad632011-03-07Martin Stjernholm  mpz_t den, f; size_t strings = 0, twos, fives, prec;
137a3e2011-03-05Martin Stjernholm 
82ad632011-03-07Martin Stjernholm  /* Remove from the denominator all factors 2 and 5, which are * the only ones we can compensate for with a decimal * fraction. */ mpz_init_set (den, mpq_denref (mpq));
137a3e2011-03-05Martin Stjernholm  mpz_init_set_ui (f, 2u);
82ad632011-03-07Martin Stjernholm  twos = mpz_remove (den, den, f);
137a3e2011-03-05Martin Stjernholm  mpz_set_ui (f, 5u);
82ad632011-03-07Martin Stjernholm  fives = mpz_remove (den, den, f); /* The necessary number of decimals is the same as the number of * times we have to multiply by 10 to get an integer (if the * denominator only contains factors 2 and 5). Since we * "consume" one factor 2 and one factor 5 every time, that * means we need the same number of 10's as the max of the 2's * and 5's. */ prec = MAXIMUM (twos, fives); if (prec) { mpz_t num; mpz_init (num); mpz_ui_pow_ui (num, 10, prec); mpz_mul (num, num, mpq_numref (mpq)); if (twos) mpz_tdiv_q_2exp (num, num, twos); if (fives) { mpz_pow_ui (f, f, fives);
91d0102014-10-14Martin Nilsson #ifdef PIKE_DEBUG
82ad632011-03-07Martin Stjernholm  assert (mpz_divisible_p (num, f));
f2db7b2014-01-04Henrik Grubbström (Grubba) #endif
82ad632011-03-07Martin Stjernholm  mpz_tdiv_q (num, num, f); }
f22ec82011-03-08Martin Stjernholm  format_dec_frac (num, prec);
82ad632011-03-07Martin Stjernholm  strings++; mpz_clear (num); } else { push_string (low_get_mpz_digits (mpq_numref (mpq), 10)); strings++; if (dec_fract >= 2) { push_constant_text (".0"); strings++; } }
137a3e2011-03-05Martin Stjernholm 
82ad632011-03-07Martin Stjernholm  /* If the denominator contains other factors we still need to * display it. */ if (mpz_cmp_ui (den, 1u)) {
5e9fc02015-08-18Per Hedbor  push_static_text ("/");
82ad632011-03-07Martin Stjernholm  push_string (low_get_mpz_digits (den, 10)); strings += 2;
137a3e2011-03-05Martin Stjernholm  }
82ad632011-03-07Martin Stjernholm  mpz_clear (den); mpz_clear (f); if (strings > 1) f_add (strings);
d4bf622001-08-13Fredrik Hübinette (Hubbe)  }
82ad632011-03-07Martin Stjernholm  else { push_string(low_get_mpz_digits(mpq_numref(mpq),10));
75367d2014-08-22Arne Goedeke  push_static_text("/");
82ad632011-03-07Martin Stjernholm  push_string(low_get_mpz_digits(mpq_denref(mpq),10)); f_add(3); }
137a3e2011-03-05Martin Stjernholm  } /*! @decl string get_string (void|int decimal_fraction) *!
82ad632011-03-07Martin Stjernholm  *! If @[decimal_fraction] is zero or left out, the number is *! returned as a string on the form @expr{"numerator/denominator"@},
b230322011-03-08Martin Stjernholm  *! where both parts are decimal integers. The numerator may be *! negative, but the denominator is always positive.
82ad632011-03-07Martin Stjernholm  *! *! If @[decimal_fraction] is set, then the number is returned as a *! (possibly negative) decimal fraction, i.e. a decimal number with
b230322011-03-08Martin Stjernholm  *! a decimal point somewhere inside. There is always at least one *! digit before and after the decimal point.
137a3e2011-03-05Martin Stjernholm  *!
82ad632011-03-07Martin Stjernholm  *! If the number can be accurately described that way, i.e. without *! an infinite number of decimals, then no denominator is included. *! Otherwise the remaining denominator is added to the decimal *! fraction after a "/". For example, 4711/100 is returned as *! @expr{"47.11"@}, 4711/200 as @expr{"23.555"@}, and 4711/300 as *! @expr{"47.11/3"@}.
137a3e2011-03-05Martin Stjernholm  *!
82ad632011-03-07Martin Stjernholm  *! If @[decimal_fraction] is 1 then the decimal fraction contains a *! '.' only if there are decimals in it. If it is 2 or higher then *! the decimal fraction always contains a '.' with at least one
b230322011-03-08Martin Stjernholm  *! digit before and after it. *! *! @note *! In any case, there are no unnecessary padding zeroes at the *! beginning or end of any decimal number.
137a3e2011-03-05Martin Stjernholm  */ PIKEFUN string get_string (void|zero|int decimal_fraction) { format_string (THISMPQ, decimal_fraction); }
0705f72011-03-05Martin Stjernholm  /*! @decl int num() *! *! Returns the numerator. */ PIKEFUN int num() { push_object (fast_clone_object (bignum_program)); mpz_set (OBTOMPZ (sp[-1].u.object), mpq_numref (THISMPQ)); reduce_stack_top_bignum(); } /*! @decl int den() *! *! Returns the denominator. It is always positive. */ PIKEFUN int den() { push_object (fast_clone_object (bignum_program)); mpz_set (OBTOMPZ (sp[-1].u.object), mpq_denref (THISMPQ)); reduce_stack_top_bignum(); }
afcf782003-03-28Martin Stjernholm  static int lookup(const char *name,
d4bf622001-08-13Fredrik Hübinette (Hubbe)  struct mapping *m, char *ind,
afcf782003-03-28Martin Stjernholm  int def, int arg, int args)
486f872016-06-08Per Hedbor  { struct svalue *sv; if((sv=simple_mapping_string_lookup(m,ind)))
d4bf622001-08-13Fredrik Hübinette (Hubbe)  {
486f872016-06-08Per Hedbor  if(TYPEOF(*sv) == T_INT)
d4bf622001-08-13Fredrik Hübinette (Hubbe)  {
486f872016-06-08Per Hedbor  return sv->u.integer; }else{
212c392018-02-25Martin Nilsson  bad_arg_error (name, args, arg, NULL, Pike_sp + arg - 1 - args,
486f872016-06-08Per Hedbor  "Bad argument %d to %s(). " "The field \"%s\" doesn't hold an integer.\n", arg, name, ind);
d4bf622001-08-13Fredrik Hübinette (Hubbe)  } }
486f872016-06-08Per Hedbor  return def; }
13670c2015-05-25Martin Nilsson 
7cfb2e2014-10-01Per Hedbor  /*! @decl protected string _sprintf(int c, mapping flags)
8388f92003-09-01Martin Nilsson  */
d4bf622001-08-13Fredrik Hübinette (Hubbe)  PIKEFUN string _sprintf(int c, mapping flags)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
486f872016-06-08Per Hedbor  { INT_TYPE precision;
d4bf622001-08-13Fredrik Hübinette (Hubbe) 
486f872016-06-08Per Hedbor  precision=lookup("Gmp.Mpq->_sprintf",flags,"precision",7, 2, args); pop_n_elems(args); if(precision<0) precision=0;
72bc912014-02-25Per Hedbor 
486f872016-06-08Per Hedbor  switch(c) { default: push_undefined(); return; case 'O': push_static_text ("Gmp.mpq("); format_string (THISMPQ, 0); push_static_text (")"); f_add (3); return; /* Fixme: Support g/e/E */ case 'g': case 'e': case 'E': case 'f':
d4bf622001-08-13Fredrik Hübinette (Hubbe)  { mpz_t tmp; mpz_init(tmp); mpz_ui_pow_ui(tmp, 10, precision); mpz_mul(tmp, tmp, mpq_numref(THISMPQ)); mpz_tdiv_q(tmp, tmp, mpq_denref(THISMPQ));
1bba242011-03-04Martin Stjernholm 
9b1c2d2011-03-05Martin Stjernholm  if (!precision)
1bba242011-03-04Martin Stjernholm  /* No dot if the precision is zero. This is consistent * with normal printf behavior. */
9b1c2d2011-03-05Martin Stjernholm  push_string (low_get_mpz_digits (tmp, 10));
f22ec82011-03-08Martin Stjernholm  else format_dec_frac (tmp, precision);
1bba242011-03-04Martin Stjernholm 
d4bf622001-08-13Fredrik Hübinette (Hubbe)  mpz_clear(tmp); } }
486f872016-06-08Per Hedbor  }
13670c2015-05-25Martin Nilsson 
7cfb2e2014-10-01Per Hedbor  /*! @decl protected int(0..1) _is_type(string arg)
8388f92003-09-01Martin Nilsson  */
7cf0162014-05-22Per Hedbor  PIKEFUN int(0..1) _is_type(string str)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
486f872016-06-08Per Hedbor  { if( str == literal_float_string ) RETURN 1; RETURN 0; }
8388f92003-09-01Martin Nilsson 
7cfb2e2014-10-01Per Hedbor  /*! @decl protected int|string|float cast(string s)
b230322011-03-08Martin Stjernholm  *! *! Casting to a string returns the number in the decimal fraction *! format, where both decimal point and quotient is included only *! if required. I.e. it is the same as calling @[get_string] with 1 *! as argument.
8388f92003-09-01Martin Nilsson  */
7cfb2e2014-10-01Per Hedbor  PIKEFUN int|string|float cast(string s)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
68ec3f2014-08-18Martin Nilsson  { pop_stack(); /* s have at least one more reference. */ if( s == literal_int_string ) f_mpq_get_int(0); else if( s == literal_string_string ) format_string (THISMPQ, 1); else if( s == literal_float_string ) f_mpq_get_float(0); else push_undefined(); }
d4bf622001-08-13Fredrik Hübinette (Hubbe) 
7cfb2e2014-10-01Per Hedbor  /*! @decl protected Gmp.mpq `+(int|float|object ... a)
8388f92003-09-01Martin Nilsson  */
486f872016-06-08Per Hedbor  PIKEFUN mpq `+(int|float|object ... UNUSED)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
486f872016-06-08Per Hedbor  { INT32 e; struct object *res; for(e=0; e<args; e++) get_mpq(sp+e-args, 1, "`+", e + 1, args); res = fast_clone_object(mpq_program); mpq_set(OBTOMPQ(res), THISMPQ); for(e=0;e<args;e++) mpq_add(OBTOMPQ(res), OBTOMPQ(res), OBTOMPQ(sp[e-args].u.object));
72bc912014-02-25Per Hedbor 
486f872016-06-08Per Hedbor  RETURN res; }
8388f92003-09-01Martin Nilsson 
7cfb2e2014-10-01Per Hedbor  /*! @decl protected Gmp.mpq ``+(int|float|object ... a)
8388f92003-09-01Martin Nilsson  */
7cfb2e2014-10-01Per Hedbor  PIKEFUN mpq ``+(int|float|object ... UNUSED)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
486f872016-06-08Per Hedbor  { INT32 e; struct object *res; for(e=0; e<args; e++) get_mpq(sp+e-args, 1, "``+", e + 1, args); res = fast_clone_object(mpq_program); mpq_set(OBTOMPQ(res), THISMPQ); for(e=0;e<args;e++) mpq_add(OBTOMPQ(res), OBTOMPQ(res), OBTOMPQ(sp[e-args].u.object));
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  RETURN res; }
d4bf622001-08-13Fredrik Hübinette (Hubbe) 
7cfb2e2014-10-01Per Hedbor  /*! @decl protected Gmp.mpq `+=(int|float|object ... a)
8388f92003-09-01Martin Nilsson  */
7cfb2e2014-10-01Per Hedbor  PIKEFUN mpq `+=(int|float|object ... UNUSED)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
d4bf622001-08-13Fredrik Hübinette (Hubbe)  { INT32 e; for(e=0; e<args; e++)
de22f72014-08-25Martin Nilsson  get_mpq(sp+e-args, 1, "`+=", e + 1, args);
d4bf622001-08-13Fredrik Hübinette (Hubbe)  for(e=0;e<args;e++) mpq_add(THISMPQ, THISMPQ, OBTOMPQ(sp[e-args].u.object));
13670c2015-05-25Martin Nilsson 
d4bf622001-08-13Fredrik Hübinette (Hubbe)  REF_RETURN fp->current_object; }
13670c2015-05-25Martin Nilsson 
d4bf622001-08-13Fredrik Hübinette (Hubbe)  #ifdef BIG_PIKE_INT #define TOOBIGTEST || sp[e-args].u.integer>MAX_INT32 #else
13670c2015-05-25Martin Nilsson #define TOOBIGTEST
d4bf622001-08-13Fredrik Hübinette (Hubbe) #endif
afcf782003-03-28Martin Stjernholm  static void mult_convert_args(INT32 args, const char *arg_func)
486f872016-06-08Per Hedbor  { INT32 e; for(e=0; e<args; e++)
d4bf622001-08-13Fredrik Hübinette (Hubbe)  {
486f872016-06-08Per Hedbor  if(TYPEOF(sp[e-args]) == T_OBJECT)
d4bf622001-08-13Fredrik Hübinette (Hubbe)  {
486f872016-06-08Per Hedbor  if(sp[e-args].u.object->prog == mpzmod_program) continue;
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  if(sp[e-args].u.object->prog == bignum_program) continue;
d4bf622001-08-13Fredrik Hübinette (Hubbe)  }
486f872016-06-08Per Hedbor  if(TYPEOF(sp[e-args]) != T_INT || sp[e-args].u.integer<=0 TOOBIGTEST) get_mpq(sp+e-args, 1, arg_func, e + 1, args);
d4bf622001-08-13Fredrik Hübinette (Hubbe)  }
486f872016-06-08Per Hedbor  }
13670c2015-05-25Martin Nilsson 
d4bf622001-08-13Fredrik Hübinette (Hubbe)  static void mult_args(MP_RAT *res, INT32 e, INT32 args)
486f872016-06-08Per Hedbor  { int norm=0; for(;e<args;e++)
d4bf622001-08-13Fredrik Hübinette (Hubbe)  {
486f872016-06-08Per Hedbor  if(TYPEOF(sp[e-args]) == T_INT)
d4bf622001-08-13Fredrik Hübinette (Hubbe)  {
486f872016-06-08Per Hedbor  mpz_mul_ui(mpq_numref(res), mpq_numref(res), sp[e-args].u.integer); norm++; } else if(sp[e-args].u.object->prog == mpq_program) { mpq_mul(res, res, OBTOMPQ(sp[e-args].u.object)); }else{ norm++; mpz_mul(mpq_numref(res), mpq_numref(res), OBTOMPZ(sp[e-args].u.object));
d4bf622001-08-13Fredrik Hübinette (Hubbe)  } }
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  if(norm) mpq_canonicalize(res); }
7cfb2e2014-10-01Per Hedbor  /*! @decl protected Gmp.mpq `*(int|float|object ... a)
8388f92003-09-01Martin Nilsson  */
7cfb2e2014-10-01Per Hedbor  PIKEFUN mpq `*(int|float|object ... UNUSED)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
486f872016-06-08Per Hedbor  { struct object *res; mult_convert_args(args, "Gmp.mpq->`*");
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  res = fast_clone_object(mpq_program); mpq_set(OBTOMPQ(res), THISMPQ); mult_args(OBTOMPQ(res), 0,args);
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  RETURN res; }
d4bf622001-08-13Fredrik Hübinette (Hubbe) 
7cfb2e2014-10-01Per Hedbor  /*! @decl protected Gmp.mpq ``*(int|float|object ... a)
8388f92003-09-01Martin Nilsson  */
7cfb2e2014-10-01Per Hedbor  PIKEFUN mpq ``*(int|float|object ... UNUSED)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
486f872016-06-08Per Hedbor  { struct object *res; mult_convert_args(args, "Gmp.mpq->``*");
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  res = fast_clone_object(mpq_program); mpq_set(OBTOMPQ(res), THISMPQ); mult_args(OBTOMPQ(res), 0,args);
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  RETURN res; }
d4bf622001-08-13Fredrik Hübinette (Hubbe) 
7cfb2e2014-10-01Per Hedbor  /*! @decl protected Gmp.mpq `-(int|float|object ... a)
8388f92003-09-01Martin Nilsson  */
7cfb2e2014-10-01Per Hedbor  PIKEFUN mpq `-(int|float|object ... UNUSED)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
486f872016-06-08Per Hedbor  { INT32 e; struct object *res;
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  if (args) for (e = 0; e<args; e++) get_mpq(sp + e - args, 1, "`-", e + 1, args);
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  res = fast_clone_object(mpq_program); mpq_set(OBTOMPQ(res), THISMPQ);
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  if(args) { for(e=0;e<args;e++) mpq_sub(OBTOMPQ(res), OBTOMPQ(res), OBTOMPQ(sp[e-args].u.object)); }else{ mpq_neg(OBTOMPQ(res), OBTOMPQ(res));
d4bf622001-08-13Fredrik Hübinette (Hubbe)  }
486f872016-06-08Per Hedbor  RETURN res; }
7cfb2e2014-10-01Per Hedbor  /*! @decl protected Gmp.mpq ``-(int|float|object sv)
8388f92003-09-01Martin Nilsson  */
7cfb2e2014-10-01Per Hedbor  PIKEFUN mpq ``-(int|float|object sv)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
486f872016-06-08Per Hedbor  { struct object *res; MP_RAT *a=get_mpq(sv, 1, "``-", 1, args); res = fast_clone_object(mpq_program); mpq_sub(OBTOMPQ(res), a, THISMPQ); RETURN res; }
8388f92003-09-01Martin Nilsson 
7cfb2e2014-10-01Per Hedbor  /*! @decl protected Gmp.mpq `/(int|float|object ... a)
8388f92003-09-01Martin Nilsson  */
7cfb2e2014-10-01Per Hedbor  PIKEFUN mpq `/(int|float|object ... UNUSED)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
486f872016-06-08Per Hedbor  { INT32 e; struct object *res;
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  for(e=0;e<args;e++) if (!mpq_sgn(get_mpq(sp+e-args, 1, "`/", e + 1, args))) SIMPLE_DIVISION_BY_ZERO_ERROR ("`/");
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  res = fast_clone_object(mpq_program); mpq_set(OBTOMPQ(res), THISMPQ); for(e=0;e<args;e++) mpq_div(OBTOMPQ(res), OBTOMPQ(res), OBTOMPQ(sp[e-args].u.object));
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  RETURN res; }
13670c2015-05-25Martin Nilsson 
7cfb2e2014-10-01Per Hedbor  /*! @decl protected Gmp.mpq ``/(int|float|object sv)
8388f92003-09-01Martin Nilsson  */
7cfb2e2014-10-01Per Hedbor  PIKEFUN mpq ``/(int|float|object sv)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
486f872016-06-08Per Hedbor  { MP_RAT *a; struct object *res = NULL; if(!mpq_sgn(THISMPQ)) SIMPLE_DIVISION_BY_ZERO_ERROR ("``/");
afcf782003-03-28Martin Stjernholm 
486f872016-06-08Per Hedbor  a=get_mpq(sv, 1, "``/", 1, args);
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  res=fast_clone_object(mpq_program); mpq_div(OBTOMPQ(res), a, THISMPQ);
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  RETURN res; }
d4bf622001-08-13Fredrik Hübinette (Hubbe) 
7cfb2e2014-10-01Per Hedbor  /*! @decl protected Gmp.mpq `%(int|float|object ... a)
8388f92003-09-01Martin Nilsson  *! @expr{a%b = a - floor(a/b)*b @} */
7cfb2e2014-10-01Per Hedbor  PIKEFUN mpq `%(int|float|object ... UNUSED)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
486f872016-06-08Per Hedbor  { INT32 e; struct object *_res; MP_INT tmp_int; MP_RAT *res; for(e=0;e<args;e++) if (!mpq_sgn(get_mpq(sp+e-args, 1, "`%", e, args))) SIMPLE_DIVISION_BY_ZERO_ERROR ("`%");
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  _res = fast_clone_object(mpq_program);
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  mpz_init(&tmp_int); mpq_set((res=OBTOMPQ(_res)), THISMPQ);
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  for(e=0;e<args;e++) { // save A denom mpz_set( &tmp_int, mpq_denref(res)); // mult A sides with B denom mpz_mul( mpq_denref(res),mpq_denref(res), mpq_denref(OBTOMPQ(sp[e-args].u.object))); mpz_mul( mpq_numref(res),mpq_numref(res), mpq_denref(OBTOMPQ(sp[e-args].u.object))); // tmp_int = B num * old A denom // (B denom would be same as A:s after multiplication, but there // is no need to do the calculation..) mpz_mul( &tmp_int, mpq_numref(OBTOMPQ(sp[e-args].u.object)), &tmp_int ); // a.num = (A.num % B.num) (since denom is common) mpz_tdiv_r( mpq_numref(res), mpq_numref(res), &tmp_int); /* This could be done after the loop, but the denominators might get out of hand. */ mpq_canonicalize(res);
d4bf622001-08-13Fredrik Hübinette (Hubbe)  }
486f872016-06-08Per Hedbor  mpz_clear(&tmp_int); RETURN _res; }
d4bf622001-08-13Fredrik Hübinette (Hubbe) 
7cfb2e2014-10-01Per Hedbor  /*! @decl protected Gmp.mpq ``%(int|float|object a)
8388f92003-09-01Martin Nilsson  */
7cfb2e2014-10-01Per Hedbor  PIKEFUN mpq ``%(int|float|object UNUSED)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
486f872016-06-08Per Hedbor  { get_mpq(sp-1, 1, "``%", 1, 1); ref_push_object(Pike_fp->current_object); apply_lfun( Pike_sp[-2].u.object, LFUN_MOD, 1 ); }
d4bf622001-08-13Fredrik Hübinette (Hubbe) 
8388f92003-09-01Martin Nilsson  /*! @decl Gmp.mpq invert() */
7cfb2e2014-10-01Per Hedbor  PIKEFUN mpq invert()
486f872016-06-08Per Hedbor  { struct object *res; if (!mpq_sgn(THISMPQ)) SIMPLE_DIVISION_BY_ZERO_ERROR ("invert"); res = fast_clone_object(mpq_program); mpq_inv(OBTOMPQ(res), THISMPQ); RETURN res; }
13670c2015-05-25Martin Nilsson 
7cfb2e2014-10-01Per Hedbor  /*! @decl protected Gmp.mpq `~()
8388f92003-09-01Martin Nilsson  *! Defined as @expr{-1-x@}. */
7cfb2e2014-10-01Per Hedbor  PIKEFUN mpq `~()
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
486f872016-06-08Per Hedbor  { struct object *o; o=fast_clone_object(mpq_program); mpq_set_si(OBTOMPQ(o), -1, 1); mpq_sub(OBTOMPQ(o),OBTOMPQ(o), THISMPQ);
13670c2015-05-25Martin Nilsson 
486f872016-06-08Per Hedbor  RETURN o; }
d4bf622001-08-13Fredrik Hübinette (Hubbe) 
7cfb2e2014-10-01Per Hedbor  /*! @decl protected int(0..1) `>(mixed q)
8388f92003-09-01Martin Nilsson  */ PIKEFUN int(0..1) `>(mixed q)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
486f872016-06-08Per Hedbor  { RETURN mpq_cmp(THISMPQ, get_mpq(q, 1, "`>", 1, args)) > 0; }
d4bf622001-08-13Fredrik Hübinette (Hubbe) 
7cfb2e2014-10-01Per Hedbor  /*! @decl protected int(0..1) `<(mixed q)
8388f92003-09-01Martin Nilsson  */ PIKEFUN int(0..1) `<(mixed q)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
486f872016-06-08Per Hedbor  { RETURN mpq_cmp(THISMPQ, get_mpq(q, 1, "`<", 1, args)) < 0; }
8388f92003-09-01Martin Nilsson 
d4bf622001-08-13Fredrik Hübinette (Hubbe) 
7cfb2e2014-10-01Per Hedbor  /*! @decl protected int(0..1) `==(mixed q)
8388f92003-09-01Martin Nilsson  */ PIKEFUN int(0..1) `==(mixed q)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
d4bf622001-08-13Fredrik Hübinette (Hubbe)  {
afcf782003-03-28Martin Stjernholm  MP_RAT *arg=get_mpq(q, 0, NULL, 0, 0);
d4bf622001-08-13Fredrik Hübinette (Hubbe)  RETURN arg && !mpq_cmp(THISMPQ, arg); }
8388f92003-09-01Martin Nilsson  /*! @decl int(-1..1) sgn() */ PIKEFUN int(-1..1) sgn()
d4bf622001-08-13Fredrik Hübinette (Hubbe)  { RETURN mpq_sgn(THISMPQ); }
7cfb2e2014-10-01Per Hedbor  /*! @decl protected int(0..1) `!(mixed q)
8388f92003-09-01Martin Nilsson  */ PIKEFUN int(0..1) `!()
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
486f872016-06-08Per Hedbor  { RETURN !mpq_sgn(THISMPQ); }
d4bf622001-08-13Fredrik Hübinette (Hubbe)  INIT
486f872016-06-08Per Hedbor  {
d4bf622001-08-13Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
486f872016-06-08Per Hedbor  if(!fp) Pike_fatal("ZERO FP\n"); if(!THISMPQ) Pike_fatal("ZERO THISMPQ\n");
d4bf622001-08-13Fredrik Hübinette (Hubbe) #endif
486f872016-06-08Per Hedbor  mpq_init(THISMPQ); }
13670c2015-05-25Martin Nilsson 
d4bf622001-08-13Fredrik Hübinette (Hubbe)  EXIT
8dcb7d2008-05-29Martin Stjernholm  gc_trivial;
486f872016-06-08Per Hedbor  {
d4bf622001-08-13Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
486f872016-06-08Per Hedbor  if(!fp) Pike_fatal("ZERO FP\n"); if(!THISMPQ) Pike_fatal("ZERO THISMPQ\n");
d4bf622001-08-13Fredrik Hübinette (Hubbe) #endif
486f872016-06-08Per Hedbor  mpq_clear(THISMPQ); }
ad8d052008-05-02Martin Stjernholm  GC_RECURSE {
9061492008-06-23Martin Stjernholm  if (mc_count_bytes (Pike_fp->current_object))
b3f6732008-05-11Martin Stjernholm  mc_counted_bytes +=
ad8d052008-05-02Martin Stjernholm  mpq_numref (THISMPQ)[0]._mp_alloc * sizeof (mp_limb_t) + mpq_denref (THISMPQ)[0]._mp_alloc * sizeof (mp_limb_t) + sizeof (mpq_t); }
d4bf622001-08-13Fredrik Hübinette (Hubbe) }
8388f92003-09-01Martin Nilsson /*! @endclass */ /*! @endmodule */
d4bf622001-08-13Fredrik Hübinette (Hubbe) void pike_init_mpq_module(void) { INIT } void pike_exit_mpq_module(void) { EXIT }