[gnome-calculator/60-split-out-a-backend-library] gcal: removing unnecessary dependencies
- From: Daniel Espinosa Ortiz <despinosa src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-calculator/60-split-out-a-backend-library] gcal: removing unnecessary dependencies
- Date: Wed, 2 Jan 2019 17:25:29 +0000 (UTC)
commit 96963528337b0444adf5dfed7c4dceeb750f9b22
Author: Daniel Espinosa Ortiz <esodan gmail com>
Date: Wed Jan 2 11:23:21 2019 -0600
gcal: removing unnecessary dependencies
This is removing almost core functionality in GCalc,
because parsing/lexer and calculation usin Number.
A reimplementation of some parts are required.
gcalc/gcalc-gexpression.vala | 7 +-
gcalc/gcalc-gsolver.vala | 12 +-
gcalc/gcalc-number.vala | 1423 +-------------------
gcalc/meson.build | 11 -
gcalc/gcalc-currency.vala => lib/currency.vala | 0
.../equation-lexer.vala | 0
.../equation-parser.vala | 0
gcalc/gcalc-equation.vala => lib/equation.vala | 0
.../function-manager.vala | 0
.../math-function.vala | 0
.../math-variables.vala | 0
lib/meson.build | 18 +-
lib/number.vala | 1416 +++++++++++++++++++
gcalc/gcalc-serializer.vala => lib/serializer.vala | 0
.../unit-manager.vala | 0
tests/meson.build | 13 +-
16 files changed, 1457 insertions(+), 1443 deletions(-)
---
diff --git a/gcalc/gcalc-gexpression.vala b/gcalc/gcalc-gexpression.vala
index 715755bd..53614b6b 100644
--- a/gcalc/gcalc-gexpression.vala
+++ b/gcalc/gcalc-gexpression.vala
@@ -19,13 +19,8 @@
* Daniel Espinosa <esodan gmail com>
*/
public class GCalc.GExpression : Object {
- public GCalc.Number number { get; set; }
- public GExpression.number_object (Number number) {
- this.number = number;
- }
public string to_string () {
- var ser = new Serializer (DisplayFormat.AUTOMATIC, 10, 10);
- return ser.to_string (number);
+ return "";
}
}
diff --git a/gcalc/gcalc-gsolver.vala b/gcalc/gcalc-gsolver.vala
index 95ff3856..61aabc50 100644
--- a/gcalc/gcalc-gsolver.vala
+++ b/gcalc/gcalc-gsolver.vala
@@ -19,16 +19,8 @@
* Daniel Espinosa <esodan gmail com>
*/
public class GCalc.GSolver : Object, Solver {
- private Equation equation;
public Result solve (string str) throws GLib.Error {
- equation = new Equation (str);
- ErrorCode err = ErrorCode.NONE;
- uint rpb = 0;
- var num = equation.parse (out rpb, out err);
- if (num == null) {
- throw new SolverError.EXPRESSION_ERROR ("Invalid equation. Parser error: %s", err.to_string ());
- }
- var exp = new GExpression.number_object (num) as Expression;
- return new GResult (exp) as Result;
+ var e = new GExpression () as Expression;
+ return new GResult (e) as Result;
}
}
diff --git a/gcalc/gcalc-number.vala b/gcalc/gcalc-number.vala
index abe42097..b4cfd594 100644
--- a/gcalc/gcalc-number.vala
+++ b/gcalc/gcalc-number.vala
@@ -1,1416 +1,19 @@
/*
- * Copyright (C) 1987-2008 Sun Microsystems, Inc. All Rights Reserved.
- * Copyright (C) 2008-2012 Robert Ancell
+ * Copyright (C) 2008-2012 Robert Ancell.
* Copyright (C) 2018 Daniel Espinosa <esodan gmail com>
*
- * This program is free software: you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later
- * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
- * license.
- */
-
-/* This maths library is based on the MP multi-precision floating-point
- * arithmetic package originally written in FORTRAN by Richard Brent,
- * Computer Centre, Australian National University in the 1970's.
- *
- * It has been converted from FORTRAN into C using the freely available
- * f2c translator, available via netlib on research.att.com.
- *
- * The subsequently converted C code has then been tidied up, mainly to
- * remove any dependencies on the libI77 and libF77 support libraries.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
*
- * FOR A GENERAL DESCRIPTION OF THE PHILOSOPHY AND DESIGN OF MP,
- * SEE - R. P. BRENT, A FORTRAN MULTIPLE-PRECISION ARITHMETIC
- * PACKAGE, ACM TRANS. MATH. SOFTWARE 4 (MARCH 1978), 57-70.
- * SOME ADDITIONAL DETAILS ARE GIVEN IN THE SAME ISSUE, 71-81.
- * FOR DETAILS OF THE IMPLEMENTATION, CALLING SEQUENCES ETC. SEE
- * THE MP USERS GUIDE.
- */
-
-using MPC;
-
-namespace GCalc {
-
- private delegate int BitwiseFunc (int v1, int v2);
-
- public enum AngleUnit
- {
- RADIANS,
- DEGREES,
- GRADIANS
- }
-
- /* Object for a high precision floating point number representation */
- public class Number : Object
- {
- /* real and imaginary part of a Number */
-
- internal Complex num = Complex (1000);
-
- construct {
- MPFR.Precision _mpfr_precision = 1000;
- precision = new Precision.internal_precision (_mpfr_precision);
- }
-
- public Precision precision { get; set; }
-
- /* Stores the error msg if an error occurs during calculation. Otherwise should be null */
- public static string? error { get; set; default = null; }
-
- public Number.integer (int64 real, int64 imag = 0, Precision? precision = null)
- {
- if (precision != null) {
- this.precision = precision;
- num.set_prec (precision._mpfr_precision);
- }
- num.set_signed_integer ((long) real, (long) imag);
- }
-
- public Number.unsigned_integer (uint64 real, uint64 imag = 0, Precision? precision = null)
- {
- if (precision != null) {
- this.precision = precision;
- num.set_prec (precision._mpfr_precision);
- }
- num.set_unsigned_integer ((ulong) real, (ulong) imag);
- }
-
- public Number.fraction (int64 numerator, int64 denominator, Precision? precision = null)
- {
- if (precision != null) {
- this.precision = precision;
- num.set_prec (precision._mpfr_precision);
- }
-
- if (denominator < 0)
- {
- numerator = -numerator;
- denominator = -denominator;
- }
-
- this.integer (numerator);
- if (denominator != 1)
- {
- num.divide_unsigned_integer (num, (long) denominator);
- }
- }
-
- /* Helper constructor. Creates new Number from already existing MPFR.Real. */
- internal Number.mpreal (MPFR.Real real, MPFR.Real? imag = null, Precision? precision = null)
- {
- if (precision != null) {
- this.precision = precision;
- num.set_prec (precision._mpfr_precision);
- }
- num.set_mpreal (real, imag);
- }
-
- public Number.double (double real, double imag = 0, Precision? precision = null)
- {
- if (precision != null) {
- this.precision = precision;
- num.set_prec (precision._mpfr_precision);
- }
- num.set_double (real, imag);
- }
-
- public Number.complex (Number r, Number i, Precision? precision = null)
- {
- if (precision != null) {
- this.precision = precision;
- num.set_prec (precision._mpfr_precision);
- }
- num.set_mpreal (r.num.get_real ().val, i.num.get_real ().val);
- }
-
- public Number.polar (Number r, Number theta, AngleUnit unit = AngleUnit.RADIANS, Precision? precision
= null)
- {
- if (precision != null) {
- this.precision = precision;
- num.set_prec (precision._mpfr_precision);
- }
- var x = theta.cos (unit);
- var y = theta.sin (unit);
- this.complex (x.multiply (r), y.multiply (r));
- }
-
- public Number.eulers (Precision? precision = null)
- {
- if (precision != null) {
- this.precision = precision;
- num.set_prec (precision._mpfr_precision);
- }
- num.get_real ().val.set_unsigned_integer (1);
- /* e^1, since mpfr doesn't have a function to return e */
- num.get_real ().val.exp (num.get_real ().val);
- num.get_imag ().val.set_zero ();
- }
-
- public Number.i (Precision? precision = null)
- {
- if (precision != null) {
- this.precision = precision;
- num.set_prec (precision._mpfr_precision);
- }
- num.set_signed_integer (0, 1);
- }
-
- public Number.pi (Precision? precision = null)
- {
- if (precision != null) {
- this.precision = precision;
- num.set_prec (precision._mpfr_precision);
- }
- num.get_real ().val.const_pi ();
- num.get_imag ().val.set_zero ();
- }
-
- /* Sets z to be a uniform random number in the range [0, 1] */
- public Number.random (Precision? precision = null)
- {
- if (precision != null) {
- this.precision = precision;
- num.set_prec (precision._mpfr_precision);
- }
- this.double (Random.next_double ());
- }
-
- public int64 to_integer ()
- {
- return num.get_real ().val.get_signed_integer ();
- }
-
- public uint64 to_unsigned_integer ()
- {
- return num.get_real ().val.get_unsigned_integer ();
- }
-
- public float to_float ()
- {
- return num.get_real ().val.get_float (MPFR.Round.NEAREST);
- }
-
- public double to_double ()
- {
- return num.get_real ().val.get_double (MPFR.Round.NEAREST);
- }
-
- /* Return true if the value is x == 0 */
- public bool is_zero ()
- {
- return num.is_zero ();
- }
-
- /* Return true if x < 0 */
- public bool is_negative ()
- {
- return num.get_real ().val.sgn () < 0;
- }
-
- /* Return true if x is integer */
- public bool is_integer ()
- {
- if (is_complex ())
- return false;
-
- return num.get_real ().val.is_integer () != 0;
- }
-
- /* Return true if x is a positive integer */
- public bool is_positive_integer ()
- {
- if (is_complex ())
- return false;
- else
- return num.get_real ().val.sgn () >= 0 && is_integer ();
- }
-
- /* Return true if x is a natural number (an integer ≥ 0) */
- public bool is_natural ()
- {
- if (is_complex ())
- return false;
- else
- return num.get_real ().val.sgn () > 0 && is_integer ();
- }
-
- /* Return true if x has an imaginary component */
- public bool is_complex ()
- {
- return !num.get_imag ().val.is_zero ();
- }
-
- /* Return error if overflow or underflow */
- public static void check_flags ()
- {
- if (MPFR.mpfr_is_underflow () != 0)
- {
- /* Translators: Error displayed when underflow error occured */
- error = _("Underflow error");
- }
- else if (MPFR.mpfr_is_overflow () != 0)
- {
- /* Translators: Error displayed when overflow error occured */
- error = _("Overflow error");
- }
- }
-
- /* Return true if x == y */
- public bool equals (Number y)
- {
- return num.is_equal (y.num);
- }
-
- /* Returns:
- * 0 if x == y
- * <0 if x < y
- * >0 if x > y
- */
- public int compare (Number y)
- {
- return num.get_real ().val.cmp (y.num.get_real ().val);
- }
-
- /* Sets z = sgn (x) */
- public Number sgn ()
- {
- var z = new Number.integer (num.get_real ().val.sgn ());
- return z;
- }
-
- /* Sets z = −x */
- public Number invert_sign ()
- {
- var z = new Number ();
- z.num.neg (num);
- return z;
- }
-
- /* Sets z = |x| */
- public Number abs ()
- {
- var z = new Number ();
- z.num.get_imag ().val.set_zero ();
- MPC.abs (z.num.get_real ().val, num);
- return z;
- }
-
- /* Sets z = Arg (x) */
- public Number arg (AngleUnit unit = AngleUnit.RADIANS)
- {
- if (is_zero ())
- {
- /* Translators: Error display when attempting to take argument of zero */
- error = _("Argument not defined for zero");
- return new Number.integer (0);
- }
- var z = new Number ();
- z.num.get_imag ().val.set_zero ();
- MPC.arg (z.num.get_real ().val, num);
- mpc_from_radians (z.num, z.num, unit);
- // MPC returns -π for the argument of negative real numbers if
- // their imaginary part is -0 (which it is in the numbers
- // created by test-equation), we want +π for all real negative
- // numbers
- if (!is_complex () && is_negative ())
- z.num.get_real ().val.abs (z.num.get_real ().val);
-
- return z;
- }
-
- /* Sets z = ‾̅x */
- public Number conjugate ()
- {
- var z = new Number ();
- z.num.conj (num);
- return z;
- }
-
- /* Sets z = Re (x) */
- public Number real_component ()
- {
- var z = new Number ();
- z.num.set_mpreal (num.get_real ().val);
- return z;
- }
-
- /* Sets z = Im (x) */
- public Number imaginary_component ()
- {
- /* Copy imaginary component to real component */
- var z = new Number ();
- z.num.set_mpreal (num.get_imag ().val);
- return z;
- }
-
- public Number integer_component ()
- {
- var z = new Number ();
- z.num.get_imag ().val.set_zero ();
- z.num.get_real ().val.trunc (num.get_real ().val);
- return z;
- }
-
- /* Sets z = x mod 1 */
- public Number fractional_component ()
- {
- var z = new Number ();
- z.num.get_imag ().val.set_zero ();
- z.num.get_real ().val.frac (num.get_real ().val);
- return z;
- }
-
- /* Sets z = {x} */
- public Number fractional_part ()
- {
- return subtract (floor ());
- }
-
- /* Sets z = ⌊x⌋ */
- public Number floor ()
- {
- var z = new Number ();
- z.num.get_imag ().val.set_zero ();
- z.num.get_real ().val.floor (num.get_real ().val);
- return z;
- }
-
- /* Sets z = ⌈x⌉ */
- public Number ceiling ()
- {
- var z = new Number ();
- z.num.get_imag ().val.set_zero ();
- z.num.get_real ().val.ceil (num.get_real ().val);
- return z;
- }
-
- /* Sets z = [x] */
- public Number round ()
- {
- var z = new Number ();
- z.num.get_imag ().val.set_zero ();
- z.num.get_real ().val.round (num.get_real ().val);
- return z;
- }
-
- /* Sets z = 1 ÷ x */
- public Number reciprocal ()
- {
- var z = new Number ();
- z.num.set_signed_integer (1);
- z.num.mpreal_divide (z.num.get_real ().val, num);
- return z;
- }
-
- /* Sets z = e^x */
- public Number epowy ()
- {
- var z = new Number ();
- z.num.exp (num);
- return z;
- }
-
- /* Sets z = x^y */
- public Number xpowy (Number y)
- {
- /* 0^-n invalid */
- if (is_zero () && y.is_negative ())
- {
- /* Translators: Error displayed when attempted to raise 0 to a negative re_exponent */
- error = _("The power of zero is undefined for a negative exponent");
- return new Number.integer (0);
- }
-
- /* 0^0 is indeterminate */
- if (is_zero () && y.is_zero ())
- {
- /* Translators: Error displayed when attempted to raise 0 to power of zero */
- error = _("Zero raised to zero is undefined");
- return new Number.integer (0);
- }
- if (!is_complex () && !y.is_complex () && !y.is_integer ())
- {
- var reciprocal = y.reciprocal ();
- if (reciprocal.is_integer ())
- return root (reciprocal.to_integer ());
- }
-
- var z = new Number ();
- z.num.power (num, y.num);
- return z;
- }
-
- /* Sets z = x^y */
- public Number xpowy_integer (int64 n)
- {
- /* 0^-n invalid */
- if (is_zero () && n < 0)
- {
- /* Translators: Error displayed when attempted to raise 0 to a negative re_exponent */
- error = _("The power of zero is undefined for a negative exponent");
- return new Number.integer (0);
- }
-
- /* 0^0 is indeterminate */
- if (is_zero () && n == 0)
- {
- /* Translators: Error displayed when attempted to raise 0 to power of zero */
- error = _("Zero raised to zero is undefined");
- return new Number.integer (0);
- }
- var z = new Number ();
- z.num.power_integer (num, (long) n);
- return z;
- }
-
- /* Sets z = n√x */
- public Number root (int64 n)
- {
- uint64 p;
- var z = new Number ();
- if (n < 0)
- {
- z.num.unsigned_integer_divide (1, num);
- if (n == int64.MIN)
- p = (uint64) int64.MAX + 1;
- else
- p = -n;
- } else if (n > 0) {
- z.num.@set (num);
- p = n;
- } else {
- error = _("The zeroth root of a number is undefined");
- return new Number.integer (0);
- }
-
- if (!is_complex () && (!is_negative () || (p & 1) == 1))
- {
- z.num.get_real ().val.root (z.num.get_real ().val, (ulong) p);
- z.num.get_imag().val.set_zero();
- } else {
- var tmp = MPFR.Real (precision._mpfr_precision);
- tmp.set_unsigned_integer ((ulong) p);
- tmp.unsigned_integer_divide (1, tmp);
- z.num.power_mpreal (z.num, tmp);
- }
- return z;
- }
-
- /* Sets z = √x */
- public Number sqrt ()
- {
- return root(2);
- }
-
- /* Sets z = ln x */
- public Number ln ()
- {
- /* ln (0) undefined */
- if (is_zero ())
- {
- /* Translators: Error displayed when attempting to take logarithm of zero */
- error = _("Logarithm of zero is undefined");
- return new Number.integer (0);
- }
-
- /* ln (-x) complex */
- /* FIXME: Make complex numbers optional */
- /*if (is_negative ())
- {
- // Translators: Error displayed attempted to take logarithm of negative value
- mperr (_("Logarithm of negative values is undefined"));
- return new Number.integer (0);
- }*/
-
- var z = new Number ();
- z.num.log (num);
- // MPC returns -π for the imaginary part of the log of
- // negative real numbers if their imaginary part is -0 (which
- // it is in the numbers created by test-equation), we want +π
- if (!is_complex () && is_negative ())
- z.num.get_imag ().val.abs (z.num.get_imag ().val);
-
- return z;
- }
-
- /* Sets z = log_n x */
- public Number logarithm (int64 n)
- {
- /* log (0) undefined */
- if (is_zero ())
- {
- /* Translators: Error displayed when attempting to take logarithm of zero */
- error = _("Logarithm of zero is undefined");
- return new Number.integer (0);
- }
-
- /* logn (x) = ln (x) / ln (n) */
- var t1 = new Number.integer (n);
- return ln ().divide (t1.ln ());
- }
-
- /* Sets z = x! */
- public Number factorial ()
- {
- /* 0! == 1 */
- if (is_zero ())
- return new Number.integer (1);
- if (!is_natural ())
- {
-
- /* Factorial Not defined for Complex or for negative numbers */
- if (is_negative () || is_complex ())
- {
- /* Translators: Error displayed when attempted take the factorial of a negative or complex
number */
- error = _("Factorial is only defined for non-negative real numbers");
- return new Number.integer (0);
- }
-
- var tmp = add (new Number.integer (1));
- var tmp2 = MPFR.Real (precision._mpfr_precision);
-
- /* Factorial(x) = Gamma(x+1) - This is the formula used to calculate Factorial.*/
- tmp2.gamma (tmp.num.get_real ().val);
-
- return new Number.mpreal (tmp2);
- }
-
- /* Convert to integer - if couldn't be converted then the factorial would be too big anyway */
- var value = to_integer ();
- var z = this;
- for (var i = 2; i < value; i++)
- z = z.multiply_integer (i);
-
- return z;
- }
-
- /* Sets z = x + y */
- public Number add (Number y)
- {
- var z = new Number ();
- z.num.add (num, y.num);
- return z;
- }
-
- /* Sets z = x − y */
- public Number subtract (Number y)
- {
- var z = new Number ();
- z.num.subtract (num, y.num);
- return z;
- }
-
- /* Sets z = x × y */
- public Number multiply (Number y)
- {
- var z = new Number ();
- z.num.multiply (num, y.num);
- return z;
- }
-
- /* Sets z = x × y */
- public Number multiply_integer (int64 y)
- {
- var z = new Number ();
- z.num.multiply_signed_integer (num, (long) y);
- return z;
- }
-
- /* Sets z = x ÷ y */
- public Number divide (Number y)
- {
- if (y.is_zero ())
- {
- /* Translators: Error displayed attempted to divide by zero */
- error = _("Division by zero is undefined");
- return new Number.integer (0);
- }
-
- var z = new Number ();
- z.num.divide (num, y.num);
- return z;
- }
-
- /* Sets z = x ÷ y */
- public Number divide_integer (int64 y)
- {
- return divide (new Number.integer (y));
- }
-
- /* Sets z = x mod y */
- public Number modulus_divide (Number y)
- {
- if (!is_integer () || !y.is_integer ())
- {
- /* Translators: Error displayed when attemping to do a modulus division on non-integer numbers
*/
- error = _("Modulus division is only defined for integers");
- return new Number.integer (0);
- }
-
- var t1 = divide (y).floor ();
- var t2 = t1.multiply (y);
- var z = subtract (t2);
-
- t1 = new Number.integer (0);
- if ((y.compare (t1) < 0 && z.compare (t1) > 0) || (y.compare (t1) > 0 && z.compare (t1) < 0))
- z = z.add (y);
-
- return z;
- }
-
- /* Sets z = x ^ y mod p */
- public Number modular_exponentiation (Number exp, Number mod)
- {
- var base_value = copy ();
- if (exp.is_negative ())
- base_value = base_value.reciprocal ();
- var exp_value = exp.abs ();
- var ans = new Number.integer (1);
- var two = new Number.integer (2);
- while (!exp_value.is_zero ())
- {
- bool is_even = exp_value.modulus_divide (two).is_zero ();
- if (!is_even)
- {
- ans = ans.multiply (base_value);
- ans = ans.modulus_divide (mod);
- }
- base_value = base_value.multiply (base_value);
- base_value = base_value.modulus_divide (mod);
- exp_value = exp_value.divide_integer (2).floor ();
- }
- return ans.modulus_divide (mod);
- }
-
- /* Sets z = sin x */
- public Number sin (AngleUnit unit = AngleUnit.RADIANS)
- {
- var z = new Number ();
- if (is_complex ())
- z.num.@set (num);
- else
- mpc_to_radians (z.num, num, unit);
- z.num.sin (z.num);
- return z;
- }
-
- /* Sets z = cos x */
- public Number cos (AngleUnit unit = AngleUnit.RADIANS)
- {
- var z = new Number ();
- if (is_complex ())
- z.num.@set (num);
- else
- mpc_to_radians (z.num, num, unit);
- z.num.cos (z.num);
- return z;
- }
-
- /* Sets z = tan x */
- public Number tan (AngleUnit unit = AngleUnit.RADIANS)
- {
- /* Check for undefined values */
- var x_radians = to_radians (unit);
- var check = x_radians.subtract (new Number.pi ().divide_integer (2)).divide (new Number.pi ());
-
- if (check.is_integer ())
- {
- /* Translators: Error displayed when tangent value is undefined */
- error = _("Tangent is undefined for angles that are multiples of π (180°) from π∕2 (90°)");
- return new Number.integer (0);
- }
-
- var z = new Number ();
- if (is_complex ())
- z.num.@set (num);
- else
- mpc_to_radians (z.num, num, unit);
- z.num.tan (z.num);
- return z;
- }
-
- /* Sets z = sin⁻¹ x */
- public Number asin (AngleUnit unit = AngleUnit.RADIANS)
- {
- if (compare (new Number.integer (1)) > 0 || compare (new Number.integer (-1)) < 0)
- {
- /* Translators: Error displayed when inverse sine value is undefined */
- error = _("Inverse sine is undefined for values outside [-1, 1]");
- return new Number.integer (0);
- }
-
- var z = new Number ();
- z.num.asin (num);
- if (!z.is_complex ())
- mpc_from_radians (z.num, z.num, unit);
- return z;
- }
-
- /* Sets z = cos⁻¹ x */
- public Number acos (AngleUnit unit = AngleUnit.RADIANS)
- {
- if (compare (new Number.integer (1)) > 0 || compare (new Number.integer (-1)) < 0)
- {
- /* Translators: Error displayed when inverse cosine value is undefined */
- error = _("Inverse cosine is undefined for values outside [-1, 1]");
- return new Number.integer (0);
- }
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
- var z = new Number ();
- z.num.acos (num);
- if (!z.is_complex ())
- mpc_from_radians (z.num, z.num, unit);
- return z;
- }
-
- /* Sets z = tan⁻¹ x */
- public Number atan (AngleUnit unit = AngleUnit.RADIANS)
- {
- var z = new Number ();
- z.num.atan (num);
- if (!z.is_complex ())
- mpc_from_radians (z.num, z.num, unit);
- return z;
- }
-
- /* Sets z = sinh x */
- public Number sinh ()
- {
- var z = new Number ();
- z.num.sinh (num);
- return z;
- }
-
- /* Sets z = cosh x */
- public Number cosh ()
- {
- var z = new Number ();
- z.num.cosh (num);
- return z;
- }
-
- /* Sets z = tanh x */
- public Number tanh ()
- {
- var z = new Number ();
- z.num.tanh (num);
- return z;
- }
-
- /* Sets z = sinh⁻¹ x */
- public Number asinh ()
- {
- var z = new Number ();
- z.num.asinh (num);
- return z;
- }
-
- /* Sets z = cosh⁻¹ x */
- public Number acosh ()
- {
- /* Check x >= 1 */
- var t = new Number.integer (1);
- if (compare (t) < 0)
- {
- /* Translators: Error displayed when inverse hyperbolic cosine value is undefined */
- error = _("Inverse hyperbolic cosine is undefined for values less than one");
- return new Number.integer (0);
- }
-
- var z = new Number ();
- z.num.acosh (num);
- return z;
- }
-
- /* Sets z = tanh⁻¹ x */
- public Number atanh ()
- {
- /* Check -1 <= x <= 1 */
- if (compare (new Number.integer (1)) >= 0 || compare (new Number.integer (-1)) <= 0)
- {
- /* Translators: Error displayed when inverse hyperbolic tangent value is undefined */
- error = _("Inverse hyperbolic tangent is undefined for values outside [-1, 1]");
- return new Number.integer (0);
- }
-
- var z = new Number ();
- z.num.atanh (num);
- return z;
- }
-
- /* Sets z = boolean AND for each bit in x and z */
- public Number and (Number y)
- {
- if (!
- is_positive_integer () || !y.is_positive_integer ())
- {
- /* Translators: Error displayed when boolean AND attempted on non-integer values */
- error = _("Boolean AND is only defined for positive integers");
- }
-
- return bitwise (y, (v1, v2) => { return v1 & v2; }, 0);
- }
-
- /* Sets z = boolean OR for each bit in x and z */
- public Number or (Number y)
- {
- if (!is_positive_integer () || !y.is_positive_integer ())
- {
- /* Translators: Error displayed when boolean OR attempted on non-integer values */
- error = _("Boolean OR is only defined for positive integers");
- }
-
- return bitwise (y, (v1, v2) => { return v1 | v2; }, 0);
- }
-
- /* Sets z = boolean XOR for each bit in x and z */
- public Number xor (Number y)
- {
- if (!is_positive_integer () || !y.is_positive_integer ())
- {
- /* Translators: Error displayed when boolean XOR attempted on non-integer values */
- error = _("Boolean XOR is only defined for positive integers");
- }
-
- return bitwise (y, (v1, v2) => { return v1 ^ v2; }, 0);
- }
-
- /* Sets z = boolean NOT for each bit in x and z for word of length 'wordlen' */
- public Number not (int wordlen)
- {
- if (!is_positive_integer ())
- {
- /* Translators: Error displayed when boolean XOR attempted on non-integer values */
- error = _("Boolean NOT is only defined for positive integers");
- }
-
- return bitwise (new Number.integer (0), (v1, v2) => { return v1 ^ 0xF; }, wordlen);
- }
-
- /* Sets z = x masked to 'wordlen' bits */
- public Number mask (Number x, int wordlen)
- {
- /* Convert to a hexadecimal string and use last characters */
- var text = x.to_hex_string ();
- var len = text.length;
- var offset = wordlen / 4;
- offset = len > offset ? (int) len - offset: 0;
- return mp_set_from_string (text.substring (offset), 16);
- }
-
- /* Sets z = x shifted by 'count' bits. Positive shift increases the value, negative decreases */
- public Number shift (int count)
- {
- if (!is_integer ())
- {
- /* Translators: Error displayed when bit shift attempted on non-integer values */
- error = _("Shift is only possible on integer values");
- return new Number.integer (0);
- }
-
- if (count >= 0)
- {
- var multiplier = 1;
- for (var i = 0; i < count; i++)
- multiplier *= 2;
- return multiply_integer (multiplier);
- }
- else
- {
- var multiplier = 1;
- for (var i = 0; i < -count; i++)
- multiplier *= 2;
- return divide_integer (multiplier).floor ();
- }
- }
-
- /* Sets z to be the ones complement of x for word of length 'wordlen' */
- public Number ones_complement (int wordlen)
- {
- return bitwise (new Number.integer (0), (v1, v2) => { return v1 ^ v2; }, wordlen).not (wordlen);
- }
-
- /* Sets z to be the twos complement of x for word of length 'wordlen' */
- public Number twos_complement (int wordlen)
- {
- return ones_complement (wordlen).add (new Number.integer (1));
- }
-
- /* Returns a list of all prime factors in x as Numbers */
- public List<Number?> factorize ()
- {
- var factors = new List<Number?> ();
-
- var value = abs ();
-
- if (value.is_zero ())
- {
- factors.append (value);
- return factors;
- }
-
- if (value.equals (new Number.integer (1)))
- {
- factors.append (this);
- return factors;
- }
-
- // if value < 2^64-1, call for factorize_uint64 function which deals in integers
-
- uint64 num = 1;
- num = num << 63;
- num += (num - 1);
- var int_max = new Number.unsigned_integer (num);
-
- if (value.compare (int_max) <= 0)
- {
- var factors_int64 = factorize_uint64 (value.to_unsigned_integer ());
- if (is_negative ())
- factors_int64.data = factors_int64.data.invert_sign ();
- return factors_int64;
- }
-
- var divisor = new Number.integer (2);
- while (true)
- {
- var tmp = value.divide (divisor);
- if (tmp.is_integer ())
- {
- value = tmp;
- factors.append (divisor);
- }
- else
- break;
- }
-
- divisor = new Number.integer (3);
- var root = value.sqrt ();
- while (divisor.compare (root) <= 0)
- {
- var tmp = value.divide (divisor);
- if (tmp.is_integer ())
- {
- value = tmp;
- root = value.sqrt ();
- factors.append (divisor);
- }
- else
- {
- tmp = divisor.add (new Number.integer (2));
- divisor = tmp;
- }
- }
-
- if (value.compare (new Number.integer (1)) > 0)
- factors.append (value);
-
- if (is_negative ())
- factors.data = factors.data.invert_sign ();
-
- return factors;
- }
-
- public List<Number?> factorize_uint64 (uint64 n)
- {
- var factors = new List<Number?> ();
- while (n % 2 == 0)
- {
- n /= 2;
- factors.append (new Number.unsigned_integer (2));
- }
-
- for (uint64 divisor = 3; divisor <= n / divisor; divisor += 2)
- {
- while (n % divisor == 0)
- {
- n /= divisor;
- factors.append (new Number.unsigned_integer (divisor));
- }
- }
-
- if (n > 1)
- factors.append (new Number.unsigned_integer (n));
- return factors;
- }
-
- private Number copy ()
- {
- var z = new Number ();
- z.num.@set (num);
- return z;
- }
-
- private void mpc_from_radians (Complex res, Complex op, AngleUnit unit)
- {
- int i;
-
- switch (unit)
- {
- default:
- case AngleUnit.RADIANS:
- if (res != op)
- res.@set (op);
- return;
-
- case AngleUnit.DEGREES:
- i = 180;
- break;
-
- case AngleUnit.GRADIANS:
- i=200;
- break;
-
- }
- var scale = MPFR.Real (precision._mpfr_precision);
- scale.const_pi ();
- scale.signed_integer_divide (i, scale);
- res.multiply_mpreal (op, scale);
- }
-
- private void mpc_to_radians (Complex res, Complex op, AngleUnit unit)
- {
- int i;
-
- switch (unit)
- {
- default:
- case AngleUnit.RADIANS:
- if (res != op)
- res.@set (op);
- return;
-
- case AngleUnit.DEGREES:
- i = 180;
- break;
-
- case AngleUnit.GRADIANS:
- i=200;
- break;
- }
- var scale = MPFR.Real (precision._mpfr_precision);
- scale.const_pi ();
- scale.divide_signed_integer (scale, i);
- res.multiply_mpreal (op, scale);
- }
-
- /* Convert x to radians */
- private Number to_radians (AngleUnit unit)
- {
- var z = new Number ();
- mpc_to_radians (z.num, num, unit);
- return z;
- }
-
- private Number bitwise (Number y, BitwiseFunc bitwise_operator, int wordlen)
- {
- var text1 = to_hex_string ();
- var text2 = y.to_hex_string ();
- var offset1 = text1.length - 1;
- var offset2 = text2.length - 1;
- var offset_out = wordlen / 4 - 1;
- if (offset_out <= 0)
- offset_out = offset1 > offset2 ? offset1 : offset2;
- if (offset_out > 0 && (offset_out < offset1 || offset_out < offset2))
- {
- error = ("Overflow. Try a bigger word size");
- return new Number.integer (0);
- }
-
- var text_out = new char[offset_out + 2];
-
- /* Perform bitwise operator on each character from right to left */
- for (text_out[offset_out+1] = '\0'; offset_out >= 0; offset_out--)
- {
- int v1 = 0, v2 = 0;
- const char digits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
'E', 'F' };
-
- if (offset1 >= 0)
- {
- v1 = hex_to_int (text1[offset1]);
- offset1--;
- }
- if (offset2 >= 0)
- {
- v2 = hex_to_int (text2[offset2]);
- offset2--;
- }
- text_out[offset_out] = digits[bitwise_operator (v1, v2)];
- }
-
- return mp_set_from_string ((string) text_out, 16);
- }
-
- private int hex_to_int (char digit)
- {
- if (digit >= '0' && digit <= '9')
- return digit - '0';
- if (digit >= 'A' && digit <= 'F')
- return digit - 'A' + 10;
- if (digit >= 'a' && digit <= 'f')
- return digit - 'a' + 10;
- return 0;
- }
-
- private string to_hex_string ()
- {
- var serializer = new Serializer (DisplayFormat.FIXED, 16, 0);
- return serializer.to_string (this);
- }
- public class Precision : Object {
- internal MPFR.Precision _mpfr_precision;
-
- construct {
- _mpfr_precision = 1000;
- }
-
- public ulong precision { get { return (ulong) _mpfr_precision; } }
-
- internal Precision.internal_precision (MPFR.Precision precision) {
- _mpfr_precision = precision;
- }
- public Precision (ulong precision) {
- _mpfr_precision = (MPFR.Precision) precision;
- }
- }
- public class Real : Object {
- internal MPFR.Real _value;
- public Real (Precision precision) {
- _value = MPFR.Real (precision._mpfr_precision);
- }
- }
- }
-
- private static int parse_literal_prefix (string str, ref int prefix_len)
- {
- var new_base = 0;
-
- if (str.length < 3 || str[0] != '0')
- return new_base;
-
- var prefix = str[1].tolower ();
-
- if (prefix == 'b')
- new_base = 2;
- else if (prefix == 'o')
- new_base = 8;
- else if (prefix == 'x')
- new_base = 16;
-
- if (new_base != 0)
- prefix_len = 2;
-
- if (prefix.isdigit ())
- {
- unichar c;
- bool all_digits = true;
-
- for (int i = 2; str.get_next_char (ref i, out c) && all_digits;)
- all_digits = c.isdigit ();
-
- if (all_digits)
- new_base = 8;
- }
-
- return new_base;
- }
-
- // FIXME: Should all be in the class
-
- // FIXME: Re-add overflow and underflow detection
-
- /* Sets z from a string representation in 'text'. */
- public Number? mp_set_from_string (string str, int default_base = 10)
- {
- if (str.index_of_char ('°') >= 0)
- return set_from_sexagesimal (str);
-
- /* Find the base */
- const unichar base_digits[] = {'₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉'};
- var index = 0;
- var base_prefix = 0;
- unichar c;
- while (str.get_next_char (ref index, out c));
- var end = index;
- var number_base = 0;
- var literal_base = 0;
- var base_multiplier = 1;
- while (str.get_prev_char (ref index, out c))
- {
- var value = -1;
- for (var i = 0; i < base_digits.length; i++)
- {
- if (c == base_digits[i])
- {
- value = i;
- break;
- }
- }
- if (value < 0)
- break;
-
- end = index;
- number_base += value * base_multiplier;
- base_multiplier *= 10;
- }
-
- literal_base = parse_literal_prefix (str, ref base_prefix);
-
- if (number_base != 0 && literal_base != 0 && literal_base != number_base)
- return null;
-
- if (number_base == 0)
- number_base = (literal_base != 0) ? literal_base : default_base;
-
- /* Check if this has a sign */
- var negate = false;
- index = base_prefix;
- str.get_next_char (ref index, out c);
- if (c == '+')
- negate = false;
- else if (c == '-' || c == '−')
- negate = true;
- else
- str.get_prev_char (ref index, out c);
-
- /* Convert integer part */
- var z = new Number.integer (0);
-
- while (str.get_next_char (ref index, out c))
- {
- var i = char_val (c, number_base);
- if (i > number_base)
- return null;
- if (i < 0)
- {
- str.get_prev_char (ref index, out c);
- break;
- }
-
- z = z.multiply_integer (number_base).add (new Number.integer (i));
- }
-
- /* Look for fraction characters, e.g. ⅚ */
- const unichar fractions[] = {'½', '⅓', '⅔', '¼', '¾', '⅕', '⅖', '⅗', '⅘', '⅙', '⅚', '⅛', '⅜', '⅝',
'⅞'};
- const int numerators[] = { 1, 1, 2, 1, 3, 1, 2, 3, 4, 1, 5, 1, 3, 5, 7};
- const int denominators[] = { 2, 3, 3, 4, 4, 5, 5, 5, 5, 6, 6, 8, 8, 8, 8};
- var has_fraction = false;
- if (str.get_next_char (ref index, out c))
- {
- for (var i = 0; i < fractions.length; i++)
- {
- if (c == fractions[i])
- {
- var fraction = new Number.fraction (numerators[i], denominators[i]);
- z = z.add (fraction);
-
- /* Must end with fraction */
- if (!str.get_next_char (ref index, out c))
- return z;
- else
- return null;
- }
- }
-
- /* Check for decimal point */
- if (c == '.')
- has_fraction = true;
- else
- str.get_prev_char (ref index, out c);
- }
-
- /* Convert fractional part */
- if (has_fraction)
- {
- var numerator = new Number.integer (0);
- var denominator = new Number.integer (1);
-
- while (str.get_next_char (ref index, out c))
- {
- var i = char_val (c, number_base);
- if (i < 0)
- {
- str.get_prev_char (ref index, out c);
- break;
- }
-
- denominator = denominator.multiply_integer (number_base);
- numerator = numerator.multiply_integer (number_base);
- numerator = numerator.add (new Number.integer (i));
- }
-
- numerator = numerator.divide (denominator);
- z = z.add (numerator);
- }
-
- if (index != end)
- return null;
-
- if (negate)
- z = z.invert_sign ();
-
- return z;
- }
-
- private int char_val (unichar c, int number_base)
- {
- if (!c.isxdigit ())
- return -1;
-
- var value = c.xdigit_value ();
-
- if (value >= number_base)
- return -1;
-
- return value;
- }
-
- private Number? set_from_sexagesimal (string str)
- {
- var degree_index = str.index_of_char ('°');
- if (degree_index < 0)
- return null;
- var degrees = mp_set_from_string (str.substring (0, degree_index));
- if (degrees == null)
- return null;
- var minute_start = degree_index;
- unichar c;
- str.get_next_char (ref minute_start, out c);
-
- if (str[minute_start] == '\0')
- return degrees;
- var minute_index = str.index_of_char ('\'', minute_start);
- if (minute_index < 0)
- return null;
- var minutes = mp_set_from_string (str.substring (minute_start, minute_index - minute_start));
- if (minutes == null)
- return null;
- degrees = degrees.add (minutes.divide_integer (60));
- var second_start = minute_index;
- str.get_next_char (ref second_start, out c);
-
- if (str[second_start] == '\0')
- return degrees;
- var second_index = str.index_of_char ('"', second_start);
- if (second_index < 0)
- return null;
- var seconds = mp_set_from_string (str.substring (second_start, second_index - second_start));
- if (seconds == null)
- return null;
- degrees = degrees.add (seconds.divide_integer (3600));
- str.get_next_char (ref second_index, out c);
-
- /* Skip over second marker and expect no more characters */
- if (str[second_index] == '\0')
- return degrees;
- else
- return null;
- }
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
- /* Returns true if x is cannot be represented in a binary word of length 'wordlen' */
- public bool mp_is_overflow (Number x, int wordlen)
- {
- var t2 = new Number.integer (2).xpowy_integer (wordlen);
- return t2.compare (x) > 0;
- }
-}
+public class
diff --git a/gcalc/meson.build b/gcalc/meson.build
index ae978daf..cb7bab62 100644
--- a/gcalc/meson.build
+++ b/gcalc/meson.build
@@ -39,25 +39,15 @@ configure_file(output : 'config.h',
configuration : confh)
sources = files([
- 'gcalc-currency.vala',
- 'gcalc-equation.vala',
- 'gcalc-equation-parser.vala',
- 'gcalc-equation-lexer.vala',
'gcalc-expression.vala',
'gcalc-error-result.vala',
- 'gcalc-function-manager.vala',
'gcalc-gexpression.vala',
'gcalc-gresult.vala',
'gcalc-gsolver.vala',
'gcalc-math-equation.vala',
'gcalc-math-equation-manager.vala',
- 'gcalc-math-function.vala',
- 'gcalc-math-variables.vala',
- 'gcalc-number.vala',
'gcalc-result.vala',
- 'gcalc-serializer.vala',
'gcalc-solver.vala',
- 'gcalc-unit-manager.vala'
])
@@ -72,7 +62,6 @@ deps = [
posix,
libxml,
libsoup,
- inc_rooth_dep
]
diff --git a/gcalc/gcalc-currency.vala b/lib/currency.vala
similarity index 100%
rename from gcalc/gcalc-currency.vala
rename to lib/currency.vala
diff --git a/gcalc/gcalc-equation-lexer.vala b/lib/equation-lexer.vala
similarity index 100%
rename from gcalc/gcalc-equation-lexer.vala
rename to lib/equation-lexer.vala
diff --git a/gcalc/gcalc-equation-parser.vala b/lib/equation-parser.vala
similarity index 100%
rename from gcalc/gcalc-equation-parser.vala
rename to lib/equation-parser.vala
diff --git a/gcalc/gcalc-equation.vala b/lib/equation.vala
similarity index 100%
rename from gcalc/gcalc-equation.vala
rename to lib/equation.vala
diff --git a/gcalc/gcalc-function-manager.vala b/lib/function-manager.vala
similarity index 100%
rename from gcalc/gcalc-function-manager.vala
rename to lib/function-manager.vala
diff --git a/gcalc/gcalc-math-function.vala b/lib/math-function.vala
similarity index 100%
rename from gcalc/gcalc-math-function.vala
rename to lib/math-function.vala
diff --git a/gcalc/gcalc-math-variables.vala b/lib/math-variables.vala
similarity index 100%
rename from gcalc/gcalc-math-variables.vala
rename to lib/math-variables.vala
diff --git a/lib/meson.build b/lib/meson.build
index 4ef01a17..d8311906 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -1,6 +1,16 @@
libcalculator_sources = files ([
'financial.vala',
- 'math-equation.vala'
+ 'function-manager.vala',
+ 'math-equation.vala',
+ 'math-function.vala',
+ 'number.vala',
+ 'serializer.vala',
+ 'currency.vala',
+ 'equation.vala',
+ 'equation-lexer.vala',
+ 'equation-parser.vala',
+ 'math-variables.vala',
+ 'unit-manager.vala'
])
libcalculator_vala_flags = [
@@ -14,9 +24,13 @@ libcalculator_c_flags = [
libcalculator_deps = [
gtk,
gtksourceview,
+ mpc,
mpfr,
posix,
- inc_rooth_dep
+ libxml,
+ libsoup,
+ inc_libh_dep,
+ inc_rooth_dep,
]
libcalculator = static_library('calculator', libcalculator_sources,
diff --git a/lib/number.vala b/lib/number.vala
new file mode 100644
index 00000000..abe42097
--- /dev/null
+++ b/lib/number.vala
@@ -0,0 +1,1416 @@
+/*
+ * Copyright (C) 1987-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (C) 2008-2012 Robert Ancell
+ * Copyright (C) 2018 Daniel Espinosa <esodan gmail com>
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
+ * license.
+ */
+
+/* This maths library is based on the MP multi-precision floating-point
+ * arithmetic package originally written in FORTRAN by Richard Brent,
+ * Computer Centre, Australian National University in the 1970's.
+ *
+ * It has been converted from FORTRAN into C using the freely available
+ * f2c translator, available via netlib on research.att.com.
+ *
+ * The subsequently converted C code has then been tidied up, mainly to
+ * remove any dependencies on the libI77 and libF77 support libraries.
+ *
+ * FOR A GENERAL DESCRIPTION OF THE PHILOSOPHY AND DESIGN OF MP,
+ * SEE - R. P. BRENT, A FORTRAN MULTIPLE-PRECISION ARITHMETIC
+ * PACKAGE, ACM TRANS. MATH. SOFTWARE 4 (MARCH 1978), 57-70.
+ * SOME ADDITIONAL DETAILS ARE GIVEN IN THE SAME ISSUE, 71-81.
+ * FOR DETAILS OF THE IMPLEMENTATION, CALLING SEQUENCES ETC. SEE
+ * THE MP USERS GUIDE.
+ */
+
+using MPC;
+
+namespace GCalc {
+
+ private delegate int BitwiseFunc (int v1, int v2);
+
+ public enum AngleUnit
+ {
+ RADIANS,
+ DEGREES,
+ GRADIANS
+ }
+
+ /* Object for a high precision floating point number representation */
+ public class Number : Object
+ {
+ /* real and imaginary part of a Number */
+
+ internal Complex num = Complex (1000);
+
+ construct {
+ MPFR.Precision _mpfr_precision = 1000;
+ precision = new Precision.internal_precision (_mpfr_precision);
+ }
+
+ public Precision precision { get; set; }
+
+ /* Stores the error msg if an error occurs during calculation. Otherwise should be null */
+ public static string? error { get; set; default = null; }
+
+ public Number.integer (int64 real, int64 imag = 0, Precision? precision = null)
+ {
+ if (precision != null) {
+ this.precision = precision;
+ num.set_prec (precision._mpfr_precision);
+ }
+ num.set_signed_integer ((long) real, (long) imag);
+ }
+
+ public Number.unsigned_integer (uint64 real, uint64 imag = 0, Precision? precision = null)
+ {
+ if (precision != null) {
+ this.precision = precision;
+ num.set_prec (precision._mpfr_precision);
+ }
+ num.set_unsigned_integer ((ulong) real, (ulong) imag);
+ }
+
+ public Number.fraction (int64 numerator, int64 denominator, Precision? precision = null)
+ {
+ if (precision != null) {
+ this.precision = precision;
+ num.set_prec (precision._mpfr_precision);
+ }
+
+ if (denominator < 0)
+ {
+ numerator = -numerator;
+ denominator = -denominator;
+ }
+
+ this.integer (numerator);
+ if (denominator != 1)
+ {
+ num.divide_unsigned_integer (num, (long) denominator);
+ }
+ }
+
+ /* Helper constructor. Creates new Number from already existing MPFR.Real. */
+ internal Number.mpreal (MPFR.Real real, MPFR.Real? imag = null, Precision? precision = null)
+ {
+ if (precision != null) {
+ this.precision = precision;
+ num.set_prec (precision._mpfr_precision);
+ }
+ num.set_mpreal (real, imag);
+ }
+
+ public Number.double (double real, double imag = 0, Precision? precision = null)
+ {
+ if (precision != null) {
+ this.precision = precision;
+ num.set_prec (precision._mpfr_precision);
+ }
+ num.set_double (real, imag);
+ }
+
+ public Number.complex (Number r, Number i, Precision? precision = null)
+ {
+ if (precision != null) {
+ this.precision = precision;
+ num.set_prec (precision._mpfr_precision);
+ }
+ num.set_mpreal (r.num.get_real ().val, i.num.get_real ().val);
+ }
+
+ public Number.polar (Number r, Number theta, AngleUnit unit = AngleUnit.RADIANS, Precision? precision
= null)
+ {
+ if (precision != null) {
+ this.precision = precision;
+ num.set_prec (precision._mpfr_precision);
+ }
+ var x = theta.cos (unit);
+ var y = theta.sin (unit);
+ this.complex (x.multiply (r), y.multiply (r));
+ }
+
+ public Number.eulers (Precision? precision = null)
+ {
+ if (precision != null) {
+ this.precision = precision;
+ num.set_prec (precision._mpfr_precision);
+ }
+ num.get_real ().val.set_unsigned_integer (1);
+ /* e^1, since mpfr doesn't have a function to return e */
+ num.get_real ().val.exp (num.get_real ().val);
+ num.get_imag ().val.set_zero ();
+ }
+
+ public Number.i (Precision? precision = null)
+ {
+ if (precision != null) {
+ this.precision = precision;
+ num.set_prec (precision._mpfr_precision);
+ }
+ num.set_signed_integer (0, 1);
+ }
+
+ public Number.pi (Precision? precision = null)
+ {
+ if (precision != null) {
+ this.precision = precision;
+ num.set_prec (precision._mpfr_precision);
+ }
+ num.get_real ().val.const_pi ();
+ num.get_imag ().val.set_zero ();
+ }
+
+ /* Sets z to be a uniform random number in the range [0, 1] */
+ public Number.random (Precision? precision = null)
+ {
+ if (precision != null) {
+ this.precision = precision;
+ num.set_prec (precision._mpfr_precision);
+ }
+ this.double (Random.next_double ());
+ }
+
+ public int64 to_integer ()
+ {
+ return num.get_real ().val.get_signed_integer ();
+ }
+
+ public uint64 to_unsigned_integer ()
+ {
+ return num.get_real ().val.get_unsigned_integer ();
+ }
+
+ public float to_float ()
+ {
+ return num.get_real ().val.get_float (MPFR.Round.NEAREST);
+ }
+
+ public double to_double ()
+ {
+ return num.get_real ().val.get_double (MPFR.Round.NEAREST);
+ }
+
+ /* Return true if the value is x == 0 */
+ public bool is_zero ()
+ {
+ return num.is_zero ();
+ }
+
+ /* Return true if x < 0 */
+ public bool is_negative ()
+ {
+ return num.get_real ().val.sgn () < 0;
+ }
+
+ /* Return true if x is integer */
+ public bool is_integer ()
+ {
+ if (is_complex ())
+ return false;
+
+ return num.get_real ().val.is_integer () != 0;
+ }
+
+ /* Return true if x is a positive integer */
+ public bool is_positive_integer ()
+ {
+ if (is_complex ())
+ return false;
+ else
+ return num.get_real ().val.sgn () >= 0 && is_integer ();
+ }
+
+ /* Return true if x is a natural number (an integer ≥ 0) */
+ public bool is_natural ()
+ {
+ if (is_complex ())
+ return false;
+ else
+ return num.get_real ().val.sgn () > 0 && is_integer ();
+ }
+
+ /* Return true if x has an imaginary component */
+ public bool is_complex ()
+ {
+ return !num.get_imag ().val.is_zero ();
+ }
+
+ /* Return error if overflow or underflow */
+ public static void check_flags ()
+ {
+ if (MPFR.mpfr_is_underflow () != 0)
+ {
+ /* Translators: Error displayed when underflow error occured */
+ error = _("Underflow error");
+ }
+ else if (MPFR.mpfr_is_overflow () != 0)
+ {
+ /* Translators: Error displayed when overflow error occured */
+ error = _("Overflow error");
+ }
+ }
+
+ /* Return true if x == y */
+ public bool equals (Number y)
+ {
+ return num.is_equal (y.num);
+ }
+
+ /* Returns:
+ * 0 if x == y
+ * <0 if x < y
+ * >0 if x > y
+ */
+ public int compare (Number y)
+ {
+ return num.get_real ().val.cmp (y.num.get_real ().val);
+ }
+
+ /* Sets z = sgn (x) */
+ public Number sgn ()
+ {
+ var z = new Number.integer (num.get_real ().val.sgn ());
+ return z;
+ }
+
+ /* Sets z = −x */
+ public Number invert_sign ()
+ {
+ var z = new Number ();
+ z.num.neg (num);
+ return z;
+ }
+
+ /* Sets z = |x| */
+ public Number abs ()
+ {
+ var z = new Number ();
+ z.num.get_imag ().val.set_zero ();
+ MPC.abs (z.num.get_real ().val, num);
+ return z;
+ }
+
+ /* Sets z = Arg (x) */
+ public Number arg (AngleUnit unit = AngleUnit.RADIANS)
+ {
+ if (is_zero ())
+ {
+ /* Translators: Error display when attempting to take argument of zero */
+ error = _("Argument not defined for zero");
+ return new Number.integer (0);
+ }
+ var z = new Number ();
+ z.num.get_imag ().val.set_zero ();
+ MPC.arg (z.num.get_real ().val, num);
+ mpc_from_radians (z.num, z.num, unit);
+ // MPC returns -π for the argument of negative real numbers if
+ // their imaginary part is -0 (which it is in the numbers
+ // created by test-equation), we want +π for all real negative
+ // numbers
+ if (!is_complex () && is_negative ())
+ z.num.get_real ().val.abs (z.num.get_real ().val);
+
+ return z;
+ }
+
+ /* Sets z = ‾̅x */
+ public Number conjugate ()
+ {
+ var z = new Number ();
+ z.num.conj (num);
+ return z;
+ }
+
+ /* Sets z = Re (x) */
+ public Number real_component ()
+ {
+ var z = new Number ();
+ z.num.set_mpreal (num.get_real ().val);
+ return z;
+ }
+
+ /* Sets z = Im (x) */
+ public Number imaginary_component ()
+ {
+ /* Copy imaginary component to real component */
+ var z = new Number ();
+ z.num.set_mpreal (num.get_imag ().val);
+ return z;
+ }
+
+ public Number integer_component ()
+ {
+ var z = new Number ();
+ z.num.get_imag ().val.set_zero ();
+ z.num.get_real ().val.trunc (num.get_real ().val);
+ return z;
+ }
+
+ /* Sets z = x mod 1 */
+ public Number fractional_component ()
+ {
+ var z = new Number ();
+ z.num.get_imag ().val.set_zero ();
+ z.num.get_real ().val.frac (num.get_real ().val);
+ return z;
+ }
+
+ /* Sets z = {x} */
+ public Number fractional_part ()
+ {
+ return subtract (floor ());
+ }
+
+ /* Sets z = ⌊x⌋ */
+ public Number floor ()
+ {
+ var z = new Number ();
+ z.num.get_imag ().val.set_zero ();
+ z.num.get_real ().val.floor (num.get_real ().val);
+ return z;
+ }
+
+ /* Sets z = ⌈x⌉ */
+ public Number ceiling ()
+ {
+ var z = new Number ();
+ z.num.get_imag ().val.set_zero ();
+ z.num.get_real ().val.ceil (num.get_real ().val);
+ return z;
+ }
+
+ /* Sets z = [x] */
+ public Number round ()
+ {
+ var z = new Number ();
+ z.num.get_imag ().val.set_zero ();
+ z.num.get_real ().val.round (num.get_real ().val);
+ return z;
+ }
+
+ /* Sets z = 1 ÷ x */
+ public Number reciprocal ()
+ {
+ var z = new Number ();
+ z.num.set_signed_integer (1);
+ z.num.mpreal_divide (z.num.get_real ().val, num);
+ return z;
+ }
+
+ /* Sets z = e^x */
+ public Number epowy ()
+ {
+ var z = new Number ();
+ z.num.exp (num);
+ return z;
+ }
+
+ /* Sets z = x^y */
+ public Number xpowy (Number y)
+ {
+ /* 0^-n invalid */
+ if (is_zero () && y.is_negative ())
+ {
+ /* Translators: Error displayed when attempted to raise 0 to a negative re_exponent */
+ error = _("The power of zero is undefined for a negative exponent");
+ return new Number.integer (0);
+ }
+
+ /* 0^0 is indeterminate */
+ if (is_zero () && y.is_zero ())
+ {
+ /* Translators: Error displayed when attempted to raise 0 to power of zero */
+ error = _("Zero raised to zero is undefined");
+ return new Number.integer (0);
+ }
+ if (!is_complex () && !y.is_complex () && !y.is_integer ())
+ {
+ var reciprocal = y.reciprocal ();
+ if (reciprocal.is_integer ())
+ return root (reciprocal.to_integer ());
+ }
+
+ var z = new Number ();
+ z.num.power (num, y.num);
+ return z;
+ }
+
+ /* Sets z = x^y */
+ public Number xpowy_integer (int64 n)
+ {
+ /* 0^-n invalid */
+ if (is_zero () && n < 0)
+ {
+ /* Translators: Error displayed when attempted to raise 0 to a negative re_exponent */
+ error = _("The power of zero is undefined for a negative exponent");
+ return new Number.integer (0);
+ }
+
+ /* 0^0 is indeterminate */
+ if (is_zero () && n == 0)
+ {
+ /* Translators: Error displayed when attempted to raise 0 to power of zero */
+ error = _("Zero raised to zero is undefined");
+ return new Number.integer (0);
+ }
+ var z = new Number ();
+ z.num.power_integer (num, (long) n);
+ return z;
+ }
+
+ /* Sets z = n√x */
+ public Number root (int64 n)
+ {
+ uint64 p;
+ var z = new Number ();
+ if (n < 0)
+ {
+ z.num.unsigned_integer_divide (1, num);
+ if (n == int64.MIN)
+ p = (uint64) int64.MAX + 1;
+ else
+ p = -n;
+ } else if (n > 0) {
+ z.num.@set (num);
+ p = n;
+ } else {
+ error = _("The zeroth root of a number is undefined");
+ return new Number.integer (0);
+ }
+
+ if (!is_complex () && (!is_negative () || (p & 1) == 1))
+ {
+ z.num.get_real ().val.root (z.num.get_real ().val, (ulong) p);
+ z.num.get_imag().val.set_zero();
+ } else {
+ var tmp = MPFR.Real (precision._mpfr_precision);
+ tmp.set_unsigned_integer ((ulong) p);
+ tmp.unsigned_integer_divide (1, tmp);
+ z.num.power_mpreal (z.num, tmp);
+ }
+ return z;
+ }
+
+ /* Sets z = √x */
+ public Number sqrt ()
+ {
+ return root(2);
+ }
+
+ /* Sets z = ln x */
+ public Number ln ()
+ {
+ /* ln (0) undefined */
+ if (is_zero ())
+ {
+ /* Translators: Error displayed when attempting to take logarithm of zero */
+ error = _("Logarithm of zero is undefined");
+ return new Number.integer (0);
+ }
+
+ /* ln (-x) complex */
+ /* FIXME: Make complex numbers optional */
+ /*if (is_negative ())
+ {
+ // Translators: Error displayed attempted to take logarithm of negative value
+ mperr (_("Logarithm of negative values is undefined"));
+ return new Number.integer (0);
+ }*/
+
+ var z = new Number ();
+ z.num.log (num);
+ // MPC returns -π for the imaginary part of the log of
+ // negative real numbers if their imaginary part is -0 (which
+ // it is in the numbers created by test-equation), we want +π
+ if (!is_complex () && is_negative ())
+ z.num.get_imag ().val.abs (z.num.get_imag ().val);
+
+ return z;
+ }
+
+ /* Sets z = log_n x */
+ public Number logarithm (int64 n)
+ {
+ /* log (0) undefined */
+ if (is_zero ())
+ {
+ /* Translators: Error displayed when attempting to take logarithm of zero */
+ error = _("Logarithm of zero is undefined");
+ return new Number.integer (0);
+ }
+
+ /* logn (x) = ln (x) / ln (n) */
+ var t1 = new Number.integer (n);
+ return ln ().divide (t1.ln ());
+ }
+
+ /* Sets z = x! */
+ public Number factorial ()
+ {
+ /* 0! == 1 */
+ if (is_zero ())
+ return new Number.integer (1);
+ if (!is_natural ())
+ {
+
+ /* Factorial Not defined for Complex or for negative numbers */
+ if (is_negative () || is_complex ())
+ {
+ /* Translators: Error displayed when attempted take the factorial of a negative or complex
number */
+ error = _("Factorial is only defined for non-negative real numbers");
+ return new Number.integer (0);
+ }
+
+ var tmp = add (new Number.integer (1));
+ var tmp2 = MPFR.Real (precision._mpfr_precision);
+
+ /* Factorial(x) = Gamma(x+1) - This is the formula used to calculate Factorial.*/
+ tmp2.gamma (tmp.num.get_real ().val);
+
+ return new Number.mpreal (tmp2);
+ }
+
+ /* Convert to integer - if couldn't be converted then the factorial would be too big anyway */
+ var value = to_integer ();
+ var z = this;
+ for (var i = 2; i < value; i++)
+ z = z.multiply_integer (i);
+
+ return z;
+ }
+
+ /* Sets z = x + y */
+ public Number add (Number y)
+ {
+ var z = new Number ();
+ z.num.add (num, y.num);
+ return z;
+ }
+
+ /* Sets z = x − y */
+ public Number subtract (Number y)
+ {
+ var z = new Number ();
+ z.num.subtract (num, y.num);
+ return z;
+ }
+
+ /* Sets z = x × y */
+ public Number multiply (Number y)
+ {
+ var z = new Number ();
+ z.num.multiply (num, y.num);
+ return z;
+ }
+
+ /* Sets z = x × y */
+ public Number multiply_integer (int64 y)
+ {
+ var z = new Number ();
+ z.num.multiply_signed_integer (num, (long) y);
+ return z;
+ }
+
+ /* Sets z = x ÷ y */
+ public Number divide (Number y)
+ {
+ if (y.is_zero ())
+ {
+ /* Translators: Error displayed attempted to divide by zero */
+ error = _("Division by zero is undefined");
+ return new Number.integer (0);
+ }
+
+ var z = new Number ();
+ z.num.divide (num, y.num);
+ return z;
+ }
+
+ /* Sets z = x ÷ y */
+ public Number divide_integer (int64 y)
+ {
+ return divide (new Number.integer (y));
+ }
+
+ /* Sets z = x mod y */
+ public Number modulus_divide (Number y)
+ {
+ if (!is_integer () || !y.is_integer ())
+ {
+ /* Translators: Error displayed when attemping to do a modulus division on non-integer numbers
*/
+ error = _("Modulus division is only defined for integers");
+ return new Number.integer (0);
+ }
+
+ var t1 = divide (y).floor ();
+ var t2 = t1.multiply (y);
+ var z = subtract (t2);
+
+ t1 = new Number.integer (0);
+ if ((y.compare (t1) < 0 && z.compare (t1) > 0) || (y.compare (t1) > 0 && z.compare (t1) < 0))
+ z = z.add (y);
+
+ return z;
+ }
+
+ /* Sets z = x ^ y mod p */
+ public Number modular_exponentiation (Number exp, Number mod)
+ {
+ var base_value = copy ();
+ if (exp.is_negative ())
+ base_value = base_value.reciprocal ();
+ var exp_value = exp.abs ();
+ var ans = new Number.integer (1);
+ var two = new Number.integer (2);
+ while (!exp_value.is_zero ())
+ {
+ bool is_even = exp_value.modulus_divide (two).is_zero ();
+ if (!is_even)
+ {
+ ans = ans.multiply (base_value);
+ ans = ans.modulus_divide (mod);
+ }
+ base_value = base_value.multiply (base_value);
+ base_value = base_value.modulus_divide (mod);
+ exp_value = exp_value.divide_integer (2).floor ();
+ }
+ return ans.modulus_divide (mod);
+ }
+
+ /* Sets z = sin x */
+ public Number sin (AngleUnit unit = AngleUnit.RADIANS)
+ {
+ var z = new Number ();
+ if (is_complex ())
+ z.num.@set (num);
+ else
+ mpc_to_radians (z.num, num, unit);
+ z.num.sin (z.num);
+ return z;
+ }
+
+ /* Sets z = cos x */
+ public Number cos (AngleUnit unit = AngleUnit.RADIANS)
+ {
+ var z = new Number ();
+ if (is_complex ())
+ z.num.@set (num);
+ else
+ mpc_to_radians (z.num, num, unit);
+ z.num.cos (z.num);
+ return z;
+ }
+
+ /* Sets z = tan x */
+ public Number tan (AngleUnit unit = AngleUnit.RADIANS)
+ {
+ /* Check for undefined values */
+ var x_radians = to_radians (unit);
+ var check = x_radians.subtract (new Number.pi ().divide_integer (2)).divide (new Number.pi ());
+
+ if (check.is_integer ())
+ {
+ /* Translators: Error displayed when tangent value is undefined */
+ error = _("Tangent is undefined for angles that are multiples of π (180°) from π∕2 (90°)");
+ return new Number.integer (0);
+ }
+
+ var z = new Number ();
+ if (is_complex ())
+ z.num.@set (num);
+ else
+ mpc_to_radians (z.num, num, unit);
+ z.num.tan (z.num);
+ return z;
+ }
+
+ /* Sets z = sin⁻¹ x */
+ public Number asin (AngleUnit unit = AngleUnit.RADIANS)
+ {
+ if (compare (new Number.integer (1)) > 0 || compare (new Number.integer (-1)) < 0)
+ {
+ /* Translators: Error displayed when inverse sine value is undefined */
+ error = _("Inverse sine is undefined for values outside [-1, 1]");
+ return new Number.integer (0);
+ }
+
+ var z = new Number ();
+ z.num.asin (num);
+ if (!z.is_complex ())
+ mpc_from_radians (z.num, z.num, unit);
+ return z;
+ }
+
+ /* Sets z = cos⁻¹ x */
+ public Number acos (AngleUnit unit = AngleUnit.RADIANS)
+ {
+ if (compare (new Number.integer (1)) > 0 || compare (new Number.integer (-1)) < 0)
+ {
+ /* Translators: Error displayed when inverse cosine value is undefined */
+ error = _("Inverse cosine is undefined for values outside [-1, 1]");
+ return new Number.integer (0);
+ }
+
+ var z = new Number ();
+ z.num.acos (num);
+ if (!z.is_complex ())
+ mpc_from_radians (z.num, z.num, unit);
+ return z;
+ }
+
+ /* Sets z = tan⁻¹ x */
+ public Number atan (AngleUnit unit = AngleUnit.RADIANS)
+ {
+ var z = new Number ();
+ z.num.atan (num);
+ if (!z.is_complex ())
+ mpc_from_radians (z.num, z.num, unit);
+ return z;
+ }
+
+ /* Sets z = sinh x */
+ public Number sinh ()
+ {
+ var z = new Number ();
+ z.num.sinh (num);
+ return z;
+ }
+
+ /* Sets z = cosh x */
+ public Number cosh ()
+ {
+ var z = new Number ();
+ z.num.cosh (num);
+ return z;
+ }
+
+ /* Sets z = tanh x */
+ public Number tanh ()
+ {
+ var z = new Number ();
+ z.num.tanh (num);
+ return z;
+ }
+
+ /* Sets z = sinh⁻¹ x */
+ public Number asinh ()
+ {
+ var z = new Number ();
+ z.num.asinh (num);
+ return z;
+ }
+
+ /* Sets z = cosh⁻¹ x */
+ public Number acosh ()
+ {
+ /* Check x >= 1 */
+ var t = new Number.integer (1);
+ if (compare (t) < 0)
+ {
+ /* Translators: Error displayed when inverse hyperbolic cosine value is undefined */
+ error = _("Inverse hyperbolic cosine is undefined for values less than one");
+ return new Number.integer (0);
+ }
+
+ var z = new Number ();
+ z.num.acosh (num);
+ return z;
+ }
+
+ /* Sets z = tanh⁻¹ x */
+ public Number atanh ()
+ {
+ /* Check -1 <= x <= 1 */
+ if (compare (new Number.integer (1)) >= 0 || compare (new Number.integer (-1)) <= 0)
+ {
+ /* Translators: Error displayed when inverse hyperbolic tangent value is undefined */
+ error = _("Inverse hyperbolic tangent is undefined for values outside [-1, 1]");
+ return new Number.integer (0);
+ }
+
+ var z = new Number ();
+ z.num.atanh (num);
+ return z;
+ }
+
+ /* Sets z = boolean AND for each bit in x and z */
+ public Number and (Number y)
+ {
+ if (!
+ is_positive_integer () || !y.is_positive_integer ())
+ {
+ /* Translators: Error displayed when boolean AND attempted on non-integer values */
+ error = _("Boolean AND is only defined for positive integers");
+ }
+
+ return bitwise (y, (v1, v2) => { return v1 & v2; }, 0);
+ }
+
+ /* Sets z = boolean OR for each bit in x and z */
+ public Number or (Number y)
+ {
+ if (!is_positive_integer () || !y.is_positive_integer ())
+ {
+ /* Translators: Error displayed when boolean OR attempted on non-integer values */
+ error = _("Boolean OR is only defined for positive integers");
+ }
+
+ return bitwise (y, (v1, v2) => { return v1 | v2; }, 0);
+ }
+
+ /* Sets z = boolean XOR for each bit in x and z */
+ public Number xor (Number y)
+ {
+ if (!is_positive_integer () || !y.is_positive_integer ())
+ {
+ /* Translators: Error displayed when boolean XOR attempted on non-integer values */
+ error = _("Boolean XOR is only defined for positive integers");
+ }
+
+ return bitwise (y, (v1, v2) => { return v1 ^ v2; }, 0);
+ }
+
+ /* Sets z = boolean NOT for each bit in x and z for word of length 'wordlen' */
+ public Number not (int wordlen)
+ {
+ if (!is_positive_integer ())
+ {
+ /* Translators: Error displayed when boolean XOR attempted on non-integer values */
+ error = _("Boolean NOT is only defined for positive integers");
+ }
+
+ return bitwise (new Number.integer (0), (v1, v2) => { return v1 ^ 0xF; }, wordlen);
+ }
+
+ /* Sets z = x masked to 'wordlen' bits */
+ public Number mask (Number x, int wordlen)
+ {
+ /* Convert to a hexadecimal string and use last characters */
+ var text = x.to_hex_string ();
+ var len = text.length;
+ var offset = wordlen / 4;
+ offset = len > offset ? (int) len - offset: 0;
+ return mp_set_from_string (text.substring (offset), 16);
+ }
+
+ /* Sets z = x shifted by 'count' bits. Positive shift increases the value, negative decreases */
+ public Number shift (int count)
+ {
+ if (!is_integer ())
+ {
+ /* Translators: Error displayed when bit shift attempted on non-integer values */
+ error = _("Shift is only possible on integer values");
+ return new Number.integer (0);
+ }
+
+ if (count >= 0)
+ {
+ var multiplier = 1;
+ for (var i = 0; i < count; i++)
+ multiplier *= 2;
+ return multiply_integer (multiplier);
+ }
+ else
+ {
+ var multiplier = 1;
+ for (var i = 0; i < -count; i++)
+ multiplier *= 2;
+ return divide_integer (multiplier).floor ();
+ }
+ }
+
+ /* Sets z to be the ones complement of x for word of length 'wordlen' */
+ public Number ones_complement (int wordlen)
+ {
+ return bitwise (new Number.integer (0), (v1, v2) => { return v1 ^ v2; }, wordlen).not (wordlen);
+ }
+
+ /* Sets z to be the twos complement of x for word of length 'wordlen' */
+ public Number twos_complement (int wordlen)
+ {
+ return ones_complement (wordlen).add (new Number.integer (1));
+ }
+
+ /* Returns a list of all prime factors in x as Numbers */
+ public List<Number?> factorize ()
+ {
+ var factors = new List<Number?> ();
+
+ var value = abs ();
+
+ if (value.is_zero ())
+ {
+ factors.append (value);
+ return factors;
+ }
+
+ if (value.equals (new Number.integer (1)))
+ {
+ factors.append (this);
+ return factors;
+ }
+
+ // if value < 2^64-1, call for factorize_uint64 function which deals in integers
+
+ uint64 num = 1;
+ num = num << 63;
+ num += (num - 1);
+ var int_max = new Number.unsigned_integer (num);
+
+ if (value.compare (int_max) <= 0)
+ {
+ var factors_int64 = factorize_uint64 (value.to_unsigned_integer ());
+ if (is_negative ())
+ factors_int64.data = factors_int64.data.invert_sign ();
+ return factors_int64;
+ }
+
+ var divisor = new Number.integer (2);
+ while (true)
+ {
+ var tmp = value.divide (divisor);
+ if (tmp.is_integer ())
+ {
+ value = tmp;
+ factors.append (divisor);
+ }
+ else
+ break;
+ }
+
+ divisor = new Number.integer (3);
+ var root = value.sqrt ();
+ while (divisor.compare (root) <= 0)
+ {
+ var tmp = value.divide (divisor);
+ if (tmp.is_integer ())
+ {
+ value = tmp;
+ root = value.sqrt ();
+ factors.append (divisor);
+ }
+ else
+ {
+ tmp = divisor.add (new Number.integer (2));
+ divisor = tmp;
+ }
+ }
+
+ if (value.compare (new Number.integer (1)) > 0)
+ factors.append (value);
+
+ if (is_negative ())
+ factors.data = factors.data.invert_sign ();
+
+ return factors;
+ }
+
+ public List<Number?> factorize_uint64 (uint64 n)
+ {
+ var factors = new List<Number?> ();
+ while (n % 2 == 0)
+ {
+ n /= 2;
+ factors.append (new Number.unsigned_integer (2));
+ }
+
+ for (uint64 divisor = 3; divisor <= n / divisor; divisor += 2)
+ {
+ while (n % divisor == 0)
+ {
+ n /= divisor;
+ factors.append (new Number.unsigned_integer (divisor));
+ }
+ }
+
+ if (n > 1)
+ factors.append (new Number.unsigned_integer (n));
+ return factors;
+ }
+
+ private Number copy ()
+ {
+ var z = new Number ();
+ z.num.@set (num);
+ return z;
+ }
+
+ private void mpc_from_radians (Complex res, Complex op, AngleUnit unit)
+ {
+ int i;
+
+ switch (unit)
+ {
+ default:
+ case AngleUnit.RADIANS:
+ if (res != op)
+ res.@set (op);
+ return;
+
+ case AngleUnit.DEGREES:
+ i = 180;
+ break;
+
+ case AngleUnit.GRADIANS:
+ i=200;
+ break;
+
+ }
+ var scale = MPFR.Real (precision._mpfr_precision);
+ scale.const_pi ();
+ scale.signed_integer_divide (i, scale);
+ res.multiply_mpreal (op, scale);
+ }
+
+ private void mpc_to_radians (Complex res, Complex op, AngleUnit unit)
+ {
+ int i;
+
+ switch (unit)
+ {
+ default:
+ case AngleUnit.RADIANS:
+ if (res != op)
+ res.@set (op);
+ return;
+
+ case AngleUnit.DEGREES:
+ i = 180;
+ break;
+
+ case AngleUnit.GRADIANS:
+ i=200;
+ break;
+ }
+ var scale = MPFR.Real (precision._mpfr_precision);
+ scale.const_pi ();
+ scale.divide_signed_integer (scale, i);
+ res.multiply_mpreal (op, scale);
+ }
+
+ /* Convert x to radians */
+ private Number to_radians (AngleUnit unit)
+ {
+ var z = new Number ();
+ mpc_to_radians (z.num, num, unit);
+ return z;
+ }
+
+ private Number bitwise (Number y, BitwiseFunc bitwise_operator, int wordlen)
+ {
+ var text1 = to_hex_string ();
+ var text2 = y.to_hex_string ();
+ var offset1 = text1.length - 1;
+ var offset2 = text2.length - 1;
+ var offset_out = wordlen / 4 - 1;
+ if (offset_out <= 0)
+ offset_out = offset1 > offset2 ? offset1 : offset2;
+ if (offset_out > 0 && (offset_out < offset1 || offset_out < offset2))
+ {
+ error = ("Overflow. Try a bigger word size");
+ return new Number.integer (0);
+ }
+
+ var text_out = new char[offset_out + 2];
+
+ /* Perform bitwise operator on each character from right to left */
+ for (text_out[offset_out+1] = '\0'; offset_out >= 0; offset_out--)
+ {
+ int v1 = 0, v2 = 0;
+ const char digits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
'E', 'F' };
+
+ if (offset1 >= 0)
+ {
+ v1 = hex_to_int (text1[offset1]);
+ offset1--;
+ }
+ if (offset2 >= 0)
+ {
+ v2 = hex_to_int (text2[offset2]);
+ offset2--;
+ }
+ text_out[offset_out] = digits[bitwise_operator (v1, v2)];
+ }
+
+ return mp_set_from_string ((string) text_out, 16);
+ }
+
+ private int hex_to_int (char digit)
+ {
+ if (digit >= '0' && digit <= '9')
+ return digit - '0';
+ if (digit >= 'A' && digit <= 'F')
+ return digit - 'A' + 10;
+ if (digit >= 'a' && digit <= 'f')
+ return digit - 'a' + 10;
+ return 0;
+ }
+
+ private string to_hex_string ()
+ {
+ var serializer = new Serializer (DisplayFormat.FIXED, 16, 0);
+ return serializer.to_string (this);
+ }
+ public class Precision : Object {
+ internal MPFR.Precision _mpfr_precision;
+
+ construct {
+ _mpfr_precision = 1000;
+ }
+
+ public ulong precision { get { return (ulong) _mpfr_precision; } }
+
+ internal Precision.internal_precision (MPFR.Precision precision) {
+ _mpfr_precision = precision;
+ }
+ public Precision (ulong precision) {
+ _mpfr_precision = (MPFR.Precision) precision;
+ }
+ }
+ public class Real : Object {
+ internal MPFR.Real _value;
+ public Real (Precision precision) {
+ _value = MPFR.Real (precision._mpfr_precision);
+ }
+ }
+ }
+
+ private static int parse_literal_prefix (string str, ref int prefix_len)
+ {
+ var new_base = 0;
+
+ if (str.length < 3 || str[0] != '0')
+ return new_base;
+
+ var prefix = str[1].tolower ();
+
+ if (prefix == 'b')
+ new_base = 2;
+ else if (prefix == 'o')
+ new_base = 8;
+ else if (prefix == 'x')
+ new_base = 16;
+
+ if (new_base != 0)
+ prefix_len = 2;
+
+ if (prefix.isdigit ())
+ {
+ unichar c;
+ bool all_digits = true;
+
+ for (int i = 2; str.get_next_char (ref i, out c) && all_digits;)
+ all_digits = c.isdigit ();
+
+ if (all_digits)
+ new_base = 8;
+ }
+
+ return new_base;
+ }
+
+ // FIXME: Should all be in the class
+
+ // FIXME: Re-add overflow and underflow detection
+
+ /* Sets z from a string representation in 'text'. */
+ public Number? mp_set_from_string (string str, int default_base = 10)
+ {
+ if (str.index_of_char ('°') >= 0)
+ return set_from_sexagesimal (str);
+
+ /* Find the base */
+ const unichar base_digits[] = {'₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉'};
+ var index = 0;
+ var base_prefix = 0;
+ unichar c;
+ while (str.get_next_char (ref index, out c));
+ var end = index;
+ var number_base = 0;
+ var literal_base = 0;
+ var base_multiplier = 1;
+ while (str.get_prev_char (ref index, out c))
+ {
+ var value = -1;
+ for (var i = 0; i < base_digits.length; i++)
+ {
+ if (c == base_digits[i])
+ {
+ value = i;
+ break;
+ }
+ }
+ if (value < 0)
+ break;
+
+ end = index;
+ number_base += value * base_multiplier;
+ base_multiplier *= 10;
+ }
+
+ literal_base = parse_literal_prefix (str, ref base_prefix);
+
+ if (number_base != 0 && literal_base != 0 && literal_base != number_base)
+ return null;
+
+ if (number_base == 0)
+ number_base = (literal_base != 0) ? literal_base : default_base;
+
+ /* Check if this has a sign */
+ var negate = false;
+ index = base_prefix;
+ str.get_next_char (ref index, out c);
+ if (c == '+')
+ negate = false;
+ else if (c == '-' || c == '−')
+ negate = true;
+ else
+ str.get_prev_char (ref index, out c);
+
+ /* Convert integer part */
+ var z = new Number.integer (0);
+
+ while (str.get_next_char (ref index, out c))
+ {
+ var i = char_val (c, number_base);
+ if (i > number_base)
+ return null;
+ if (i < 0)
+ {
+ str.get_prev_char (ref index, out c);
+ break;
+ }
+
+ z = z.multiply_integer (number_base).add (new Number.integer (i));
+ }
+
+ /* Look for fraction characters, e.g. ⅚ */
+ const unichar fractions[] = {'½', '⅓', '⅔', '¼', '¾', '⅕', '⅖', '⅗', '⅘', '⅙', '⅚', '⅛', '⅜', '⅝',
'⅞'};
+ const int numerators[] = { 1, 1, 2, 1, 3, 1, 2, 3, 4, 1, 5, 1, 3, 5, 7};
+ const int denominators[] = { 2, 3, 3, 4, 4, 5, 5, 5, 5, 6, 6, 8, 8, 8, 8};
+ var has_fraction = false;
+ if (str.get_next_char (ref index, out c))
+ {
+ for (var i = 0; i < fractions.length; i++)
+ {
+ if (c == fractions[i])
+ {
+ var fraction = new Number.fraction (numerators[i], denominators[i]);
+ z = z.add (fraction);
+
+ /* Must end with fraction */
+ if (!str.get_next_char (ref index, out c))
+ return z;
+ else
+ return null;
+ }
+ }
+
+ /* Check for decimal point */
+ if (c == '.')
+ has_fraction = true;
+ else
+ str.get_prev_char (ref index, out c);
+ }
+
+ /* Convert fractional part */
+ if (has_fraction)
+ {
+ var numerator = new Number.integer (0);
+ var denominator = new Number.integer (1);
+
+ while (str.get_next_char (ref index, out c))
+ {
+ var i = char_val (c, number_base);
+ if (i < 0)
+ {
+ str.get_prev_char (ref index, out c);
+ break;
+ }
+
+ denominator = denominator.multiply_integer (number_base);
+ numerator = numerator.multiply_integer (number_base);
+ numerator = numerator.add (new Number.integer (i));
+ }
+
+ numerator = numerator.divide (denominator);
+ z = z.add (numerator);
+ }
+
+ if (index != end)
+ return null;
+
+ if (negate)
+ z = z.invert_sign ();
+
+ return z;
+ }
+
+ private int char_val (unichar c, int number_base)
+ {
+ if (!c.isxdigit ())
+ return -1;
+
+ var value = c.xdigit_value ();
+
+ if (value >= number_base)
+ return -1;
+
+ return value;
+ }
+
+ private Number? set_from_sexagesimal (string str)
+ {
+ var degree_index = str.index_of_char ('°');
+ if (degree_index < 0)
+ return null;
+ var degrees = mp_set_from_string (str.substring (0, degree_index));
+ if (degrees == null)
+ return null;
+ var minute_start = degree_index;
+ unichar c;
+ str.get_next_char (ref minute_start, out c);
+
+ if (str[minute_start] == '\0')
+ return degrees;
+ var minute_index = str.index_of_char ('\'', minute_start);
+ if (minute_index < 0)
+ return null;
+ var minutes = mp_set_from_string (str.substring (minute_start, minute_index - minute_start));
+ if (minutes == null)
+ return null;
+ degrees = degrees.add (minutes.divide_integer (60));
+ var second_start = minute_index;
+ str.get_next_char (ref second_start, out c);
+
+ if (str[second_start] == '\0')
+ return degrees;
+ var second_index = str.index_of_char ('"', second_start);
+ if (second_index < 0)
+ return null;
+ var seconds = mp_set_from_string (str.substring (second_start, second_index - second_start));
+ if (seconds == null)
+ return null;
+ degrees = degrees.add (seconds.divide_integer (3600));
+ str.get_next_char (ref second_index, out c);
+
+ /* Skip over second marker and expect no more characters */
+ if (str[second_index] == '\0')
+ return degrees;
+ else
+ return null;
+ }
+
+ /* Returns true if x is cannot be represented in a binary word of length 'wordlen' */
+ public bool mp_is_overflow (Number x, int wordlen)
+ {
+ var t2 = new Number.integer (2).xpowy_integer (wordlen);
+ return t2.compare (x) > 0;
+ }
+}
diff --git a/gcalc/gcalc-serializer.vala b/lib/serializer.vala
similarity index 100%
rename from gcalc/gcalc-serializer.vala
rename to lib/serializer.vala
diff --git a/gcalc/gcalc-unit-manager.vala b/lib/unit-manager.vala
similarity index 100%
rename from gcalc/gcalc-unit-manager.vala
rename to lib/unit-manager.vala
diff --git a/tests/meson.build b/tests/meson.build
index b4f58cdc..2cbecb79 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -1,5 +1,9 @@
+if not get_option ('disable-ui')
+
# Common
gnome_calculator_tests_deps = [
+ gtk,
+ gtksourceview,
gio,
glib,
gobject,
@@ -15,12 +19,13 @@ gnome_calculator_tests_includes = [
]
# Tests
+
test_equation_sources = [
'test-equation.vala',
]
test_equation = executable('test-equation', test_equation_sources,
dependencies: gnome_calculator_tests_deps,
- link_with: [lib, lib_mpfrg],
+ link_with: [libcalculator, lib_mpfrg],
include_directories: gnome_calculator_tests_includes,
)
test('Equation test', test_equation)
@@ -30,7 +35,7 @@ test_number_sources = [
]
test_number = executable('test-number', test_number_sources,
dependencies: gnome_calculator_tests_deps,
- link_with: [lib, lib_mpfrg],
+ link_with: [libcalculator, lib_mpfrg],
include_directories: gnome_calculator_tests_includes,
)
test('Number test', test_number)
@@ -40,11 +45,11 @@ test_serializer_sources = [
]
test_serializer = executable('test-serializer', test_serializer_sources,
dependencies: gnome_calculator_tests_deps,
- link_with: [lib, lib_mpfrg],
+ link_with: [libcalculator, lib_mpfrg],
include_directories: gnome_calculator_tests_includes,
)
test('Serializer test', test_serializer)
-
+endif
test_main_interfaces_sources = [
'gcalc-main-interfaces.vala',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]