[gnome-calculator] ported to MPFR
- From: Arth Patel <arthpatel src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-calculator] ported to MPFR
- Date: Mon, 22 Dec 2014 18:42:36 +0000 (UTC)
commit 0e863eeb121d670d8f5266a82b6152e98b2428ea
Author: Daniel Renninghoff <daniel renninghoff gmail com>
Date: Wed Dec 17 21:21:57 2014 +0100
ported to MPFR
Signed-off-by: PioneerAxon <arth svnit gmail com>
data/org.gnome.calculator.gschema.xml | 6 +-
src/Makefile.am | 21 +-
src/currency.vala | 2 +-
src/equation-lexer.vala | 2 +-
src/equation-parser.vala | 125 ++-
src/equation.vala | 6 +-
src/gcalccmd.vala | 10 +-
src/gnome-calculator.vala | 6 +-
src/math-converter.vala | 2 +-
src/math-equation.vala | 85 ++-
src/math-preferences.vala | 2 +-
src/math-window.vala | 2 +-
src/mpfr.vapi | 133 ++
src/number.vala | 2478 ++++++---------------------------
src/serializer.vala | 16 +-
src/test-equation.vala | 32 +-
src/test-number.vala | 16 -
src/unit.vala | 4 +-
18 files changed, 788 insertions(+), 2160 deletions(-)
---
diff --git a/data/org.gnome.calculator.gschema.xml b/data/org.gnome.calculator.gschema.xml
index ee6684f..2a21b4e 100644
--- a/data/org.gnome.calculator.gschema.xml
+++ b/data/org.gnome.calculator.gschema.xml
@@ -21,7 +21,6 @@
<schema path="/org/gnome/calculator/" id="org.gnome.calculator" gettext-domain="calculator">
<key type="i" name="accuracy">
<default>9</default>
- <range min="0" max="9"/>
<summary>Accuracy value</summary>
<description>The number of digits displayed after the numeric point</description>
</key>
@@ -82,5 +81,10 @@
<summary>Target units</summary>
<description>Units to convert the current calculation into</description>
</key>
+ <key type="i" name="precision">
+ <default>2000</default>
+ <summary>Internal precision</summary>
+ <description>The internal precision used with the MPFR library</description>
+ </key>
</schema>
</schemalist>
diff --git a/src/Makefile.am b/src/Makefile.am
index d8a408e..d3a52d7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,6 +18,7 @@ resources.c: $(top_srcdir)/data/gnome-calculator.gresource.xml $(shell $(GLIB_CO
gnome_calculator_SOURCES = \
config.vapi \
+ mpfr.vapi \
gnome-calculator.vala \
currency.vala \
equation.vala \
@@ -50,10 +51,12 @@ gnome_calculator_VALAFLAGS = \
gnome_calculator_LDADD = \
$(GNOME_CALCULATOR_LIBS) \
- -lm
+ -lmpfr \
+ -lgmp
gcalccmd_SOURCES = \
config.vapi \
+ mpfr.vapi \
gcalccmd.vala \
currency.vala \
equation.vala \
@@ -73,10 +76,12 @@ gcalccmd_VALAFLAGS = \
gcalccmd_LDADD = \
$(GCALCCMD_LIBS) \
- -lm
+ -lmpfr \
+ -lgmp
test_number_SOURCES = \
config.vapi \
+ mpfr.vapi \
test-number.vala \
number.vala \
serializer.vala
@@ -89,10 +94,13 @@ test_number_VALAFLAGS = \
test_number_LDADD = \
$(GCALCCMD_LIBS) \
- -lm
+ -lm \
+ -lmpfr \
+ -lgmp
test_equation_SOURCES = \
config.vapi \
+ mpfr.vapi \
test-equation.vala \
currency.vala \
equation.vala \
@@ -112,10 +120,12 @@ test_equation_VALAFLAGS = \
test_equation_LDADD = \
$(GCALCCMD_LIBS) \
- -lm
+ -lmpfr \
+ -lgmp
test_serializer_SOURCES = \
config.vapi \
+ mpfr.vapi \
test-serializer.vala \
number.vala \
serializer.vala
@@ -128,6 +138,7 @@ test_serializer_VALAFLAGS = \
test_serializer_LDADD = \
$(GCALCCMD_LIBS) \
- -lm
+ -lmpfr \
+ -lgmp
-include $(top_srcdir)/git.mk
diff --git a/src/currency.vala b/src/currency.vala
index 6435599..db66ee6 100644
--- a/src/currency.vala
+++ b/src/currency.vala
@@ -444,7 +444,7 @@ public class CurrencyManager : Object
{
warning ("Couldn't download IMF currency rate file: %s", e.message);
}
-
+
downloading_imf_rates = false;
load_rates ();
}
diff --git a/src/equation-lexer.vala b/src/equation-lexer.vala
index 652769e..20731af 100644
--- a/src/equation-lexer.vala
+++ b/src/equation-lexer.vala
@@ -120,7 +120,7 @@ public class PreLexer : Object
if (c == ',' || c == '.')
return LexerTokenType.PL_DECIMAL;
-
+
if (c.isdigit ())
return LexerTokenType.PL_DIGIT;
diff --git a/src/equation-parser.vala b/src/equation-parser.vala
index d06485b..29f66bd 100644
--- a/src/equation-parser.vala
+++ b/src/equation-parser.vala
@@ -78,7 +78,20 @@ public abstract class RNode : ParseNode
var r = right.solve ();
if (r == null)
return null;
- return solve_r (r);
+ var z = solve_r (r);
+
+ /* check for errors */
+ Number.check_flags ();
+ if (Number.error != null)
+ {
+ var tmpleft = right;
+ var tmpright = right;
+ while (tmpleft.left != null) tmpleft = tmpleft.left;
+ while (tmpright.right != null) tmpright = tmpright.right;
+ parser.set_error (ErrorCode.MP, Number.error, tmpleft.token.start_index,
tmpright.token.end_index);
+ Number.error = null;
+ }
+ return z;
}
public abstract Number solve_r (Number r);
@@ -97,7 +110,20 @@ public abstract class LRNode : ParseNode
var r = right.solve ();
if (l == null || r == null)
return null;
- return solve_lr (l, r);
+ var z = solve_lr (l, r);
+
+ /* check for errors */
+ Number.check_flags ();
+ if (Number.error != null)
+ {
+ var tmpleft = left;
+ var tmpright = right;
+ while (tmpleft.left != null) tmpleft = tmpleft.left;
+ while (tmpright.right != null) tmpright = tmpright.right;
+ parser.set_error (ErrorCode.MP, Number.error, tmpleft.token.start_index,
tmpright.token.end_index);
+ Number.error = null;
+ }
+ return z;
}
public abstract Number solve_lr (Number left, Number r);
@@ -109,7 +135,7 @@ public class ConstantNode : ParseNode
{
base (parser, token, precedence, associativity);
}
-
+
public override Number? solve ()
{
return mp_set_from_string (token.text, parser.number_base);
@@ -118,7 +144,7 @@ public class ConstantNode : ParseNode
public class AssignNode : RNode
{
- public AssignNode (Parser parser, LexerToken? token, uint precedence, Associativity associativity)
+ public AssignNode (Parser parser, LexerToken? token, uint precedence, Associativity associativity)
{
base (parser, token, precedence, associativity);
}
@@ -170,7 +196,7 @@ public class VariableNode : ParseNode
}
public override Number? solve ()
- {
+ {
/* If defined, then get the variable */
var ans = parser.get_variable (token.text);
if (ans != null)
@@ -235,6 +261,18 @@ public class VariableWithPowerNode : ParseNode
value = value.multiply (t);
}
+ /* check for errors */
+ Number.check_flags ();
+ if (Number.error != null)
+ {
+ var tmpleft = left;
+ var tmpright = right;
+ while (tmpleft.left != null) tmpleft = tmpleft.left;
+ while (tmpright.right != null) tmpright = tmpright.right;
+ parser.set_error (ErrorCode.MP, Number.error, tmpleft.token.start_index,
tmpright.token.end_index);
+ Number.error = null;
+ }
+
return value;
}
}
@@ -353,6 +391,15 @@ public class FunctionNode : ParseNode
if (tmp != null)
tmp = tmp.xpowy_integer (pow);
+
+ /* check for errors */
+ Number.check_flags ();
+ if (Number.error != null)
+ {
+ parser.set_error (ErrorCode.MP, Number.error);
+ Number.error = null;
+ }
+
return tmp;
}
}
@@ -527,7 +574,17 @@ public class DivideNode : LRNode
public override Number solve_lr (Number l, Number r)
{
- return l.divide (r);
+ var z = l.divide (r);
+ if (Number.error != null)
+ {
+ var tmpleft = right;
+ var tmpright = right;
+ while (tmpleft.left != null) tmpleft = tmpleft.left;
+ while (tmpright.right != null) tmpright = tmpright.right;
+ parser.set_error (ErrorCode.MP, Number.error, tmpleft.token.start_index,
tmpright.token.end_index);
+ Number.error = null;
+ }
+ return z;
}
}
@@ -547,7 +604,21 @@ public class ModulusDivideNode : LRNode
var mod = right.solve ();
if (base_value == null || exponent == null || mod == null)
return null;
- return base_value.modular_exponentiation (exponent, mod);
+ var z = base_value.modular_exponentiation (exponent, mod);
+
+ /* check for errors */
+ Number.check_flags ();
+ if (Number.error != null)
+ {
+ var tmpleft = left;
+ var tmpright = right;
+ while (tmpleft.left != null) tmpleft = tmpleft.left;
+ while (tmpright.right != null) tmpright = tmpright.right;
+ parser.set_error (ErrorCode.MP, Number.error, tmpleft.token.start_index,
tmpright.token.end_index);
+ Number.error = null;
+ }
+
+ return z;
}
else
{
@@ -555,7 +626,21 @@ public class ModulusDivideNode : LRNode
var r = right.solve ();
if (l == null || r == null)
return null;
- return solve_lr (l, r);
+ var z = solve_lr (l, r);
+
+ /* check for errors */
+ Number.check_flags ();
+ if (Number.error != null)
+ {
+ var tmpleft = left;
+ var tmpright = right;
+ while (tmpleft.left != null) tmpleft = tmpleft.left;
+ while (tmpright.right != null) tmpright = tmpright.right;
+ parser.set_error (ErrorCode.MP, Number.error, tmpleft.token.start_index,
tmpright.token.end_index);
+ Number.error = null;
+ }
+
+ return z;
}
}
@@ -624,7 +709,21 @@ public class XPowYIntegerNode : ParseNode
if (val == null)
return null;
- return val.xpowy_integer (pow);
+ var z = val.xpowy_integer (pow);
+
+ /* check for errors */
+ Number.check_flags ();
+ if (Number.error != null)
+ {
+ var tmpleft = left;
+ var tmpright = right;
+ while (tmpleft.left != null) tmpleft = tmpleft.left;
+ while (tmpright.right != null) tmpright = tmpright.right;
+ parser.set_error (ErrorCode.MP, Number.error, tmpleft.token.start_index,
tmpright.token.end_index);
+ Number.error = null;
+ }
+
+ return z;
}
}
@@ -937,10 +1036,10 @@ public class Parser
}
representation_base = this.representation_base;
- error_code = ErrorCode.NONE;
- error_token = null;
- error_start = 0;
- error_end = 0;
+ error_code = this.error;
+ error_token = this.error_token;
+ error_start = this.error_token_start;
+ error_end = this.error_token_end;
return ans;
}
diff --git a/src/equation.vala b/src/equation.vala
index f1a0afb..3c49610 100644
--- a/src/equation.vala
+++ b/src/equation.vala
@@ -117,15 +117,17 @@ public class Equation : Object
public new Number? parse (out uint representation_base = null, out ErrorCode error_code = null, out
string? error_token = null, out uint? error_start = null, out uint? error_end = null)
{
var parser = new EquationParser (this, expression);
- mp_clear_error ();
+ Number.error = null;
var z = parser.parse (out representation_base, out error_code, out error_token, out error_start, out
error_end);
/* Error during parsing */
if (error_code != ErrorCode.NONE)
+ {
return null;
+ }
- if (mp_get_error () != null)
+ if (Number.error != null)
{
error_code = ErrorCode.MP;
return null;
diff --git a/src/gcalccmd.vala b/src/gcalccmd.vala
index 88bf3f6..dc8783e 100644
--- a/src/gcalccmd.vala
+++ b/src/gcalccmd.vala
@@ -34,9 +34,15 @@ static void solve (string equation)
result_serializer.set_representation_base (representation_base);
if (z != null)
- stdout.printf ("%s\n", result_serializer.to_string (z));
+ {
+ var str = result_serializer.to_string (z);
+ if (result_serializer.error != null)
+ stderr.printf ("%s\n", result_serializer.error);
+ else
+ stdout.printf ("%s\n", str);
+ }
else if (ret == ErrorCode.MP)
- stderr.printf ("Error %s\n", mp_get_error ());
+ stderr.printf ("Error %s\n", Number.error);
else
stderr.printf ("Error %d\n", ret);
}
diff --git a/src/gnome-calculator.vala b/src/gnome-calculator.vala
index 694d384..dc8df49 100644
--- a/src/gnome-calculator.vala
+++ b/src/gnome-calculator.vala
@@ -31,7 +31,7 @@ public class Calculator : Gtk.Application
{ "about", about_cb, null, null, null },
{ "quit", quit_cb, null, null, null },
};
-
+
public Calculator ()
{
Object (flags : ApplicationFlags.NON_UNIQUE);
@@ -56,6 +56,7 @@ public class Calculator : Gtk.Application
var target_currency = settings.get_string ("target-currency");
var source_units = settings.get_string ("source-units");
var target_units = settings.get_string ("target-units");
+ var precision = settings.get_int ("precision");
var equation = new MathEquation ();
equation.accuracy = accuracy;
@@ -68,6 +69,7 @@ public class Calculator : Gtk.Application
equation.target_currency = target_currency;
equation.source_units = source_units;
equation.target_units = target_units;
+ Number.precision = precision;
add_action_entries (app_entries, this);
@@ -171,7 +173,7 @@ public class Calculator : Gtk.Application
}
else if (error == ErrorCode.MP)
{
- stderr.printf ("Error: %s\n", mp_get_error ());
+ stderr.printf ("Error: %s\n", Number.error);
return Posix.EXIT_FAILURE;
}
else
diff --git a/src/math-converter.vala b/src/math-converter.vala
index 15eba6f..1a69dc8 100644
--- a/src/math-converter.vala
+++ b/src/math-converter.vala
@@ -18,7 +18,7 @@ public class MathConverter : Gtk.Box
private Gtk.ComboBox to_combo;
private Gtk.Label result_label;
-
+
public signal void changed ();
public MathConverter (MathEquation equation)
diff --git a/src/math-equation.vala b/src/math-equation.vala
index cb61057..fa60685 100644
--- a/src/math-equation.vala
+++ b/src/math-equation.vala
@@ -47,7 +47,7 @@ public class MathEquation : Gtk.SourceBuffer
{
private Gtk.TextTag ans_tag;
- /* Word size in bits */
+ /* Word size in bits */
private int _word_size;
public int word_size
{
@@ -781,6 +781,11 @@ public class MathEquation : Gtk.SourceBuffer
ans_start_mark = create_mark (null, start, false);
ans_end_mark = create_mark (null, end, true);
apply_tag (ans_tag, start, end);
+
+ if (serializer.error != null)
+ {
+ status = serializer.error;
+ }
}
public new void insert (string text)
@@ -954,11 +959,13 @@ public class MathEquation : Gtk.SourceBuffer
break;
case ErrorCode.MP:
- if (mp_get_error () != null)
- solvedata.error = mp_get_error ();
- else if (error_token != null) /* Uncategorized error. Show error token to user */
+ if (Number.error != null) // LEGACY, should never be run
{
- solvedata.error = _("Malformed expression at token '%s'").printf (error_token);
+ solvedata.error = Number.error;
+ }
+ else if (error_token != null) // should always be run
+ {
+ solvedata.error = _("%s").printf (error_token);
solvedata.error_start = error_start;
solvedata.error_end = error_end;
}
@@ -1003,6 +1010,8 @@ public class MathEquation : Gtk.SourceBuffer
/* Fix thousand separator offsets in the start and end offsets of error token. */
error_token_fix_thousands_separator ();
+ /* Fix missing Parenthesis before the start and after the end offsets of error token */
+ error_token_fix_parenthesis ();
/* Notify the GUI about the change in error token locations. */
notify_property ("error-token-end");
@@ -1074,6 +1083,70 @@ public class MathEquation : Gtk.SourceBuffer
}
}
+ /* Fix the offsets to consider starting and ending parenthesis */
+ private void error_token_fix_parenthesis ()
+ {
+ unichar c;
+ int count = 0;
+ int real_end = display.index_of_nth_char (error_token_end);
+ int real_start = display.index_of_nth_char (error_token_start);
+
+ /* checks if there are more opening/closing parenthesis than closing/opening parenthesis */
+ for (int i = real_start; display.get_next_char (ref i, out c) && i <= real_end;)
+ {
+ if (c.to_string () == "(") count++;
+ if (c.to_string () == ")") count--;
+ }
+
+ /* if there are more opening than closing parenthesis and there are closing parenthesis
+ after the end offset, include those in the offsets */
+ for (int i = real_end; display.get_next_char (ref i, out c) && count > 0;)
+ {
+ if (c.to_string () == ")")
+ {
+ state.error_token_end++;
+ count--;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ /* the same for closing parenthesis */
+ for (int i = real_start; display.get_prev_char (ref i, out c) && count < 0;)
+ {
+ if (c.to_string () == "(")
+ {
+ state.error_token_start--;
+ count++;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ real_end = display.index_of_nth_char (error_token_end);
+ real_start = display.index_of_nth_char (error_token_start);
+
+ unichar d;
+
+ /* if there are opening parenthesis directly before aswell as closing parenthesis directly after the
offsets, include those aswell */
+ while (display.get_next_char (ref real_end, out d) && display.get_prev_char (ref real_start, out c))
+ {
+ if (c.to_string () == "(" && d.to_string () == ")")
+ {
+ state.error_token_start--;
+ state.error_token_end++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
private void* factorize_real ()
{
var x = number;
@@ -1159,7 +1232,7 @@ public class MathEquation : Gtk.SourceBuffer
var z = number;
if (z == null)
{
- /* This message is displayed in the status bar when a bit shift operation is performed and the
display does not contain a number */
+ /* This message is displayed in the status bar when a bit shift operation is performed and the
display does not contain a number */
status = _("No sane value to bitwise shift");
return;
}
diff --git a/src/math-preferences.vala b/src/math-preferences.vala
index 525082d..d1256a1 100644
--- a/src/math-preferences.vala
+++ b/src/math-preferences.vala
@@ -90,7 +90,7 @@ public class MathPreferencesDialog : Gtk.Dialog
var string = _("Show %d decimal _places");
var tokens = string.split ("%d", 2);
- var decimal_places_adjustment = new Gtk.Adjustment (0.0, 0.0, 9.0, 1.0, 1.0, 0.0);
+ var decimal_places_adjustment = new Gtk.Adjustment (0.0, 0.0, 100.0, 1.0, 1.0, 0.0);
decimal_places_spin = new Gtk.SpinButton (decimal_places_adjustment, 0.0, 0);
if (tokens.length > 0)
diff --git a/src/math-window.vala b/src/math-window.vala
index 9690807..4ba7b07 100644
--- a/src/math-window.vala
+++ b/src/math-window.vala
@@ -90,7 +90,7 @@ public class MathWindow : Gtk.ApplicationWindow
var vbox = new Gtk.Box (Gtk.Orientation.VERTICAL, 6);
vbox.border_width = 6;
- main_vbox.pack_start (vbox, true, true, 0);
+ main_vbox.pack_start (vbox, true, true, 0);
vbox.show ();
var scrolled_window = new Gtk.ScrolledWindow (null, null);
diff --git a/src/mpfr.vapi b/src/mpfr.vapi
new file mode 100644
index 0000000..8c08cab
--- /dev/null
+++ b/src/mpfr.vapi
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2014 Daniel Renninghoff
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
+ * license.
+ */
+
+/* A small guide on using MPFR with gnome-calculator:
+ * Using it is pretty much self-explanatory when you look at the code in
+ * number.vala.
+ * C syntax: mpfr_add (result, op1, op2, MPFR_RNDN);
+ * Vala syntax: result.add (op1, op2, Round.NEAREST);
+ *
+ * The result has to be initialized with init2() before using it (same in C).
+ * Since MPFR is a C library you have to do manual memory management. This means
+ * that after init2()ing something, you have to clear() it at the end. Clearing
+ * re_num and im_num is taken are of by the destructor of Number. Just make sure
+ * to manually clear any temporary helper variables you use.
+ */
+
+[CCode (cheader_filename="mpfr.h")]
+namespace MPFR {
+ [SimpleType]
+ [IntegerType]
+ [CCode (cname = "mpfr_prec_t", has_type_id = false)]
+ public struct Precision {}
+
+ [CCode (cname = "mpfr_rnd_t", has_type_id = false)]
+ public enum Round {
+ [CCode (cname = "MPFR_RNDN")]
+ NEAREST,
+ [CCode (cname = "MPFR_RNDZ")]
+ ZERO,
+ [CCode (cname = "MPFR_RNDU")]
+ UP,
+ [CCode (cname = "MPFR_RNDD")]
+ DOWN,
+ [CCode (cname = "MPFR_RNDA")]
+ AWAY,
+ [CCode (cname = "MPFR_RNDF")]
+ FAITHFUL,
+ [CCode (cname = "MPFR_RNDNA")]
+ NEARESTAWAY
+ }
+
+ [CCode (cname = "__mpfr_struct", cprefix = "mpfr_", has_destroy_function = false, copy_function = "",
has_type_id = false)]
+ public struct MPFloat {
+ [CCode (cname="mpfr_init2")]
+ public MPFloat.init2 (Precision prec);
+
+ [CCode (cname="mpfr_set_ui")]
+ public int set_unsigned_integer (ulong op, Round rnd);
+ [CCode (cname="mpfr_set_si")]
+ public int set_signed_integer (long op, Round rnd);
+ [CCode (cname="mpfr_set_flt")]
+ public int set_float (float op, Round rnd);
+ [CCode (cname="mpfr_set_d")]
+ public int set_double (double op, Round rnd);
+ [CCode (cname="mpfr_set")]
+ public int set (MPFloat op, Round rnd);
+
+ public void clear ();
+
+ public int add (MPFloat op1, MPFloat op2, Round rnd);
+ [CCode (cname="mpfr_sub")]
+ public int subtract (MPFloat op1, MPFloat op2, Round rnd);
+ [CCode (cname="mpfr_mul")]
+ public int multiply (MPFloat op1, MPFloat op2, Round rnd);
+ [CCode (cname="mpfr_div")]
+ public int divide (MPFloat op1, MPFloat op2, Round rnd);
+
+ [CCode (cname="mpfr_get_si")]
+ public long get_signed_integer (Round rnd);
+ [CCode (cname="mpfr_get_ui")]
+ public ulong get_unsigned_integer (Round rnd);
+ [CCode (cname="mpfr_get_flt")]
+ public float get_float (Round rnd);
+ [CCode (cname="mpfr_get_d")]
+ public double get_double (Round rnd);
+
+ public int const_pi (Round rnd);
+ [CCode (cname="mpfr_zero_p")]
+ public bool is_zero ();
+ public int sgn ();
+ [CCode (cname="mpfr_equal_p")]
+ public bool is_equal (MPFloat op2);
+ public int cmp (MPFloat op2);
+ public int sqrt (MPFloat op, Round rnd);
+ public int neg (MPFloat op, Round rnd);
+ [CCode (cname="mpfr_pow_si")]
+ public int power_signed_integer (MPFloat op1, long op2, Round rnd);
+ [CCode (cname="mpfr_mul_si")]
+ public int multiply_signed_integer (MPFloat op1, long op2, Round rnd);
+ [CCode (cname="mpfr_div_si")]
+ public int divide_signed_integer (MPFloat op1, long op2, Round rnd);
+ public int floor (MPFloat op);
+ [CCode (cname="mpfr_pow")]
+ public int power (MPFloat op1, MPFloat op2, Round rnd);
+ public int exp (MPFloat op, Round rnd);
+ public int log (MPFloat op, Round rnd);
+ public int sin (MPFloat op, Round rnd);
+ public int cos (MPFloat op, Round rnd);
+ public int tan (MPFloat op, Round rnd);
+ public int asin (MPFloat op, Round rnd);
+ public int acos (MPFloat op, Round rnd);
+ public int atan (MPFloat op, Round rnd);
+ public int sinh (MPFloat op, Round rnd);
+ public int cosh (MPFloat op, Round rnd);
+ public int tanh (MPFloat op, Round rnd);
+ public int asinh (MPFloat op, Round rnd);
+ public int acosh (MPFloat op, Round rnd);
+ public int atanh (MPFloat op, Round rnd);
+ public int abs (MPFloat op, Round rnd);
+ public int root (MPFloat op, ulong k, Round rnd);
+ public int rint (MPFloat op, Round rnd);
+ public int frac (MPFloat op, Round rnd);
+ public int ceil (MPFloat op);
+ public int trunc (MPFloat op);
+ public int round (MPFloat op);
+ [CCode (cname="mpfr_integer_p")]
+ public int is_integer ();
+ public int gamma (MPFloat op, Round rnd);
+ }
+
+ [CCode (cname = "mpfr_underflow_p")]
+ public int mpfr_is_underflow ();
+
+ [CCode (cname = "mpfr_overflow_p")]
+ public int mpfr_is_overflow ();
+}
diff --git a/src/number.vala b/src/number.vala
index 3d9c01f..d6b419c 100644
--- a/src/number.vala
+++ b/src/number.vala
@@ -27,20 +27,7 @@
* THE MP USERS GUIDE.
*/
-/* Size of the multiple precision values */
-private const int SIZE = 1000;
-
-/* Base for numbers */
-private const int BASE = 10000;
-
-//2E0 BELOW ENSURES AT LEAST ONE GUARD DIGIT
-//MP.t = (int) ((float) (accuracy) * Math.log ((float)10.) / Math.log ((float) BASE) + (float) 2.0);
-//if (MP.t > SIZE)
-//{
-// mperr ("SIZE TOO SMALL IN CALL TO MPSET, INCREASE SIZE AND DIMENSIONS OF MP ARRAYS TO AT LEAST %d
***", MP.t);
-// MP.t = SIZE;
-//}
-private const int T = 100;
+using MPFR;
private delegate int BitwiseFunc (int v1, int v2);
@@ -51,75 +38,40 @@ public enum AngleUnit
GRADIANS
}
-/* Object for a high precision floating point number representation
- *
- * x = sign * (BASE^(exponent-1) + BASE^(exponent-2) + ...)
- */
+/* Object for a high precision floating point number representation */
public class Number : Object
{
- /* Sign (+1, -1) or 0 for the value zero */
- public int re_sign;
- public int im_sign;
+ /* real and imaginary part of a Number */
+ private MPFloat re_num { get; set; }
+ private MPFloat im_num { get; set; }
- /* Exponent (to base BASE) */
- public int re_exponent;
- public int im_exponent;
+ public static ulong precision { get; set; default = 1000; }
- /* Normalized fraction */
- public int re_fraction[1000]; // SIZE
- public int im_fraction[1000]; // SIZE
+ /* 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 value)
{
- if (value < 0)
- {
- value = -value;
- re_sign = -1;
- }
- else if (value > 0)
- re_sign = 1;
- else
- re_sign = 0;
-
- while (value != 0)
- {
- re_fraction[re_exponent] = (int) (value % BASE);
- re_exponent++;
- value /= BASE;
- }
- for (var i = 0; i < re_exponent / 2; i++)
- {
- int t = re_fraction[i];
- re_fraction[i] = re_fraction[re_exponent - i - 1];
- re_fraction[re_exponent - i - 1] = t;
- }
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.set_signed_integer ((long)value, Round.NEAREST);
+ re_num = tmp;
+ var tmp2 = MPFloat.init2 ((Precision) precision);
+ tmp2.set_unsigned_integer (0, Round.NEAREST);
+ im_num = tmp2;
}
public Number.unsigned_integer (uint64 x)
{
- if (x == 0)
- re_sign = 0;
- else
- re_sign = 1;
-
- while (x != 0)
- {
- re_fraction[re_exponent] = (int) (x % BASE);
- x = x / BASE;
- re_exponent++;
- }
- for (var i = 0; i < re_exponent / 2; i++)
- {
- int t = re_fraction[i];
- re_fraction[i] = re_fraction[re_exponent - i - 1];
- re_fraction[re_exponent - i - 1] = t;
- }
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.set_unsigned_integer ((ulong)x, Round.NEAREST);
+ re_num = tmp;
+ var tmp2 = MPFloat.init2 ((Precision) precision);
+ tmp2.set_unsigned_integer (0, Round.NEAREST);
+ im_num = tmp2;
}
public Number.fraction (int64 numerator, int64 denominator)
{
- mp_gcd (ref numerator, ref denominator);
-
if (denominator < 0)
{
numerator = -numerator;
@@ -129,203 +81,39 @@ public class Number : Object
Number.integer (numerator);
if (denominator != 1)
{
- var z = divide_integer (denominator);
- re_sign = z.re_sign;
- im_sign = z.im_sign;
- re_exponent = z.re_exponent;
- im_exponent = z.im_exponent;
- for (var i = 0; i < z.re_fraction.length; i++)
- {
- re_fraction[i] = z.re_fraction[i];
- im_fraction[i] = z.im_fraction[i];
- }
+ var tmp = re_num;
+ tmp.divide_signed_integer (re_num, (long) denominator, Round.NEAREST);
+ re_num = tmp;
}
}
- public Number.float (float value)
+ /* Helper constructor. Creates new Number from already existing MPFloat. */
+ public Number.mpfloat (MPFloat value)
{
- var z = new Number.integer (0);
-
- if (value != 0)
- {
- /* CHECK SIGN */
- var rj = 0f;
- if (value < 0.0f)
- {
- z.re_sign = -1;
- rj = -value;
- }
- else if (value > 0.0f)
- {
- z.re_sign = 1;
- rj = value;
- }
-
- /* INCREASE IE AND DIVIDE RJ BY 16. */
- var ie = 0;
- while (rj >= 1.0f)
- {
- ie++;
- rj *= 0.0625f;
- }
- while (rj < 0.0625f)
- {
- ie--;
- rj *= 16.0f;
- }
-
- /* NOW RJ IS DY DIVIDED BY SUITABLE POWER OF 16.
- * SET re_exponent TO 0
- */
- z.re_exponent = 0;
-
- /* CONVERSION LOOP (ASSUME SINGLE-PRECISION OPS. EXACT) */
- for (var i = 0; i < T + 4; i++)
- {
- rj *= BASE;
- z.re_fraction[i] = (int) rj;
- rj -= z.re_fraction[i];
- }
-
- /* NORMALIZE RESULT */
- mp_normalize (ref z);
-
- /* Computing MAX */
- var ib = int.max (BASE * 7 * BASE, 32767) / 16;
- var tp = 1;
-
- /* NOW MULTIPLY BY 16**IE */
- if (ie < 0)
- {
- var k = -ie;
- for (var i = 1; i <= k; i++)
- {
- tp <<= 4;
- if (tp <= ib && tp != BASE && i < k)
- continue;
- z = z.divide_integer (tp);
- tp = 1;
- }
- }
- else if (ie > 0)
- {
- for (var i = 1; i <= ie; i++)
- {
- tp <<= 4;
- if (tp <= ib && tp != BASE && i < ie)
- continue;
- z = z.multiply_integer (tp);
- tp = 1;
- }
- }
- }
-
- re_sign = z.re_sign;
- im_sign = z.im_sign;
- re_exponent = z.re_exponent;
- im_exponent = z.im_exponent;
- for (var i = 0; i < z.re_fraction.length; i++)
- {
- re_fraction[i] = z.re_fraction[i];
- im_fraction[i] = z.im_fraction[i];
- }
+ re_num = value;
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.set_unsigned_integer (0, Round.NEAREST);
+ im_num = tmp;
}
-
+
public Number.double (double value)
{
- var z = new Number.integer (0);
-
- if (value != 0)
- {
- /* CHECK SIGN */
- var dj = 0.0;
- if (value < 0.0)
- {
- z.re_sign = -1;
- dj = -value;
- }
- else if (value > 0.0)
- {
- z.re_sign = 1;
- dj = value;
- }
-
- /* INCREASE IE AND DIVIDE DJ BY 16. */
- var ie = 0;
- for (ie = 0; dj >= 1.0; ie++)
- dj *= 1.0/16.0;
-
- for ( ; dj < 1.0/16.0; ie--)
- dj *= 16.0;
-
- /* NOW DJ IS DY DIVIDED BY SUITABLE POWER OF 16
- * SET re_exponent TO 0
- */
- z.re_exponent = 0;
-
- /* CONVERSION LOOP (ASSUME DOUBLE-PRECISION OPS. EXACT) */
- for (var i = 0; i < T + 4; i++)
- {
- dj *= (double) BASE;
- z.re_fraction[i] = (int) dj;
- dj -= (double) z.re_fraction[i];
- }
-
- /* NORMALIZE RESULT */
- mp_normalize (ref z);
-
- /* Computing MAX */
- var ib = int.max (BASE * 7 * BASE, 32767) / 16;
- var tp = 1;
-
- /* NOW MULTIPLY BY 16**IE */
- if (ie < 0)
- {
- var k = -ie;
- for (var i = 1; i <= k; ++i)
- {
- tp <<= 4;
- if (tp <= ib && tp != BASE && i < k)
- continue;
- z = z.divide_integer (tp);
- tp = 1;
- }
- }
- else if (ie > 0)
- {
- for (var i = 1; i <= ie; ++i)
- {
- tp <<= 4;
- if (tp <= ib && tp != BASE && i < ie)
- continue;
- z = z.multiply_integer (tp);
- tp = 1;
- }
- }
- }
-
- re_sign = z.re_sign;
- im_sign = z.im_sign;
- re_exponent = z.re_exponent;
- im_exponent = z.im_exponent;
- for (var i = 0; i < z.re_fraction.length; i++)
- {
- re_fraction[i] = z.re_fraction[i];
- im_fraction[i] = z.im_fraction[i];
- }
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.set_double (value, Round.NEAREST);
+ re_num = tmp;
+ var tmp2 = MPFloat.init2 ((Precision) precision);
+ tmp2.set_unsigned_integer (0, Round.NEAREST);
+ im_num = tmp2;
}
public Number.complex (Number x, Number y)
{
- re_sign = x.re_sign;
- re_exponent = x.re_exponent;
- for (var i = 0; i < im_fraction.length; i++)
- re_fraction[i] = x.re_fraction[i];
-
- im_sign = y.re_sign;
- im_exponent = y.re_exponent;
- for (var i = 0; i < im_fraction.length; i++)
- im_fraction[i] = y.re_fraction[i];
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp set (x.re_num, Round.NEAREST);
+ re_num = tmp;
+ var tmp2 = MPFloat.init2 ((Precision) precision);
+ tmp2 set (y.re_num, Round.NEAREST);
+ im_num = tmp2;
}
public Number.polar (Number r, Number theta, AngleUnit unit = AngleUnit.RADIANS)
@@ -336,30 +124,36 @@ public class Number : Object
}
public Number.eulers ()
- {
- var z = new Number.integer (1).epowy ();
- re_sign = z.re_sign;
- im_sign = z.im_sign;
- re_exponent = z.re_exponent;
- im_exponent = z.im_exponent;
- for (var i = 0; i < z.re_fraction.length; i++)
- {
- re_fraction[i] = z.re_fraction[i];
- im_fraction[i] = z.im_fraction[i];
- }
+ {
+ var tmp = MPFloat.init2 ((Precision) precision);
+ var tmp2 = MPFloat.init2 ((Precision) precision);
+ tmp2.set_unsigned_integer (1, Round.NEAREST);
+ /* e^1, since mpfr doesn't have a function to return e */
+ tmp.exp (tmp2, Round.NEAREST);
+ re_num = tmp;
+ var tmp3 = MPFloat.init2 ((Precision) precision);
+ tmp3.set_unsigned_integer (0, Round.NEAREST);
+ im_num = tmp3;
}
public Number.i ()
{
- im_sign = 1;
- im_exponent = 1;
- im_fraction[0] = 1;
+ var tmp = MPFloat.init2 ((Precision) precision);
+ var tmp2 = MPFloat.init2 ((Precision) precision);
+ tmp.set_unsigned_integer (0, Round.NEAREST);
+ tmp2.set_unsigned_integer (1, Round.NEAREST);
+ re_num = tmp;
+ im_num = tmp2;
}
public Number.pi ()
{
- // FIXME: Should generate PI to required accuracy
- Number.double (Math.PI);
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.const_pi (Round.NEAREST);
+ re_num = tmp;
+ var tmp2 = MPFloat.init2 ((Precision) precision);
+ tmp2.set_unsigned_integer (0, Round.NEAREST);
+ im_num = tmp2;
}
/* Sets z to be a uniform random number in the range [0, 1] */
@@ -368,123 +162,42 @@ public class Number : Object
Number.double (Random.next_double ());
}
- public int64 to_integer ()
+ ~Number ()
{
- int64 z = 0;
-
- /* |x| <= 1 */
- if (re_sign == 0 || re_exponent <= 0)
- return 0;
-
- /* Multiply digits together */
- for (var i = 0; i < re_exponent; i++)
- {
- var t = z;
- z = z * BASE + re_fraction[i];
-
- /* Check for overflow */
- if (z <= t)
- return 0;
- }
-
- /* Validate result */
- var v = z;
- for (var i = re_exponent - 1; i >= 0; i--)
- {
- /* Get last digit */
- var digit = v - (v / BASE) * BASE;
- if (re_fraction[i] != digit)
- return 0;
-
- v /= BASE;
- }
- if (v != 0)
- return 0;
+ re_num.clear ();
+ im_num.clear ();
+ }
- return re_sign * z;
+ public int64 to_integer ()
+ {
+ return re_num.get_signed_integer (Round.NEAREST);
}
public uint64 to_unsigned_integer ()
{
- /* x <= 1 */
- if (re_sign <= 0 || re_exponent <= 0)
- return 0;
-
- /* Multiply digits together */
- uint64 z = 0;
- for (var i = 0; i < re_exponent; i++)
- {
- var t = z;
- z = z * BASE + re_fraction[i];
-
- /* Check for overflow */
- if (z <= t)
- return 0;
- }
-
- /* Validate result */
- var v = z;
- for (var i = re_exponent - 1; i >= 0; i--)
- {
- /* Get last digit */
- var digit = (uint64) v - (v / BASE) * BASE;
- if (re_fraction[i] != digit)
- return 0;
-
- v /= BASE;
- }
- if (v != 0)
- return 0;
-
- return z;
+ return re_num.get_unsigned_integer (Round.NEAREST);
}
public float to_float ()
{
- if (is_zero ())
- return 0f;
-
- var z = 0f;
- for (var i = 0; i < T; i++)
- {
- if (re_fraction[i] != 0)
- z += re_fraction[i] * Math.powf (BASE, re_exponent - i - 1);
- }
-
- if (re_sign < 0)
- return -z;
- else
- return z;
+ return re_num.get_float (Round.NEAREST);
}
public double to_double ()
{
- if (is_zero ())
- return 0d;
-
- var z = 0d;
- for (var i = 0; i < T; i++)
- {
- if (re_fraction[i] != 0)
- z += re_fraction[i] * Math.pow (BASE, re_exponent - i - 1);
- }
-
- if (re_sign < 0)
- return -z;
- else
- return z;
+ return re_num.get_double (Round.NEAREST);
}
/* Return true if the value is x == 0 */
public bool is_zero ()
{
- return re_sign == 0 && im_sign == 0;
+ return re_num.is_zero () && im_num.is_zero ();
}
/* Return true if x < 0 */
public bool is_negative ()
{
- return re_sign < 0;
+ return re_num.sgn () < 0;
}
/* Return true if x is integer */
@@ -493,36 +206,7 @@ public class Number : Object
if (is_complex ())
return false;
- /* This fix is required for 1/3 repiprocal not being detected as an integer */
- /* Multiplication and division by 10000 is used to get around a
- * limitation to the "fix" for Sun bugtraq bug #4006391 in the
- * floor () routine in mp.c, when the re_exponent is less than 1.
- */
- var t3 = new Number.integer (10000);
- var t1 = multiply (t3);
- t1 = t1.divide (t3);
- var t2 = t1.floor ();
- return t1.equals (t2);
-
- /* Correct way to check for integer */
- /*
-
- // Zero is an integer
- if (is_zero ())
- return true;
-
- // fractional
- if (re_exponent <= 0)
- return false;
-
- // Look for fractional components
- for (var i = re_exponent; i < SIZE; i++)
- {
- if (re_fraction[i] != 0)
- return false;
- }
-
- return true;*/
+ return re_num.is_integer () != 0;
}
/* Return true if x is a positive integer */
@@ -531,7 +215,7 @@ public class Number : Object
if (is_complex ())
return false;
else
- return re_sign >= 0 && is_integer ();
+ return re_num.sgn () >= 0 && is_integer ();
}
/* Return true if x is a natural number (an integer ≥ 0) */
@@ -540,19 +224,34 @@ public class Number : Object
if (is_complex ())
return false;
else
- return re_sign > 0 && is_integer ();
+ return re_num.sgn () > 0 && is_integer ();
}
/* Return true if x has an imaginary component */
public bool is_complex ()
{
- return im_sign != 0;
+ return !im_num.is_zero ();
+ }
+
+ /* Return error if overflow or underflow */
+ public static void check_flags ()
+ {
+ if (mpfr_is_underflow () != 0)
+ {
+ /* Translators: Error displayed when underflow error occured */
+ error = _("Underflow error");
+ }
+ else if (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 compare (y) == 0;
+ return re_num.is_equal (y.re_num);
}
/* Returns:
@@ -562,62 +261,25 @@ public class Number : Object
*/
public int compare (Number y)
{
- if (re_sign != y.re_sign)
- {
- if (re_sign > y.re_sign)
- return 1;
- else
- return -1;
- }
-
- /* x = y = 0 */
- if (is_zero ())
- return 0;
-
- /* See if numbers are of different magnitude */
- if (re_exponent != y.re_exponent)
- {
- if (re_exponent > y.re_exponent)
- return re_sign;
- else
- return -re_sign;
- }
-
- /* Compare fractions */
- for (var i = 0; i < SIZE; i++)
- {
- if (re_fraction[i] == y.re_fraction[i])
- continue;
-
- if (re_fraction[i] > y.re_fraction[i])
- return re_sign;
- else
- return -re_sign;
- }
-
- /* x = y */
- return 0;
+ return re_num.cmp (y.re_num);
}
/* Sets z = sgn (x) */
public Number sgn ()
{
- if (is_zero ())
- return new Number.integer (0);
- else if (is_negative ())
- return new Number.integer (-1);
- else
- return new Number.integer (1);
+ var z = new Number.integer (re_num.sgn ());
+ return z;
}
/* Sets z = −x */
public Number invert_sign ()
{
- var z = copy ();
-
- z.re_sign = -z.re_sign;
- z.im_sign = -z.im_sign;
-
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.neg (re_num, Round.NEAREST);
+ var z = new Number.mpfloat (tmp);
+ var tmp_im = z.im_num;
+ tmp_im.neg (im_num, Round.NEAREST);
+ z.im_num = tmp_im;
return z;
}
@@ -632,13 +294,13 @@ public class Number : Object
x_real = x_real.multiply (x_real);
x_im = x_im.multiply (x_im);
var z = x_real.add (x_im);
- return z.root (2);
+ return z.sqrt ();
}
else
{
- var z = copy ();
- if (z.re_sign < 0)
- z.re_sign = -z.re_sign;
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.abs (re_num, Round.NEAREST);
+ var z = new Number.mpfloat (tmp);
return z;
}
}
@@ -649,7 +311,7 @@ public class Number : Object
if (is_zero ())
{
/* Translators: Error display when attempting to take argument of zero */
- mperr (_("Argument not defined for zero"));
+ error = _("Argument not defined for zero");
return new Number.integer (0);
}
@@ -693,8 +355,12 @@ public class Number : Object
/* Sets z = ‾̅x */
public Number conjugate ()
{
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.neg (im_num, Round.NEAREST);
var z = copy ();
- z.im_sign = -z.im_sign;
+ var tmp2 = z.im_num;
+ tmp2.clear ();
+ z.im_num = tmp;
return z;
}
@@ -702,13 +368,11 @@ public class Number : Object
public Number real_component ()
{
var z = copy ();
-
- /* Clear imaginary component */
- z.im_sign = 0;
- z.im_exponent = 0;
- for (var i = 0; i < z.im_fraction.length; i++)
- z.im_fraction[i] = 0;
-
+ var tmp = z.im_num;
+ tmp.clear ();
+ tmp = MPFloat.init2 ((Precision) precision);
+ tmp.set_unsigned_integer (0, Round.NEAREST);
+ z.im_num = tmp;
return z;
}
@@ -716,64 +380,30 @@ public class Number : Object
public Number imaginary_component ()
{
/* Copy imaginary component to real component */
- var z = new Number ();
- z.re_sign = im_sign;
- z.re_exponent = im_exponent;
-
- for (var i = 0; i < z.im_fraction.length; i++)
- z.re_fraction[i] = im_fraction[i];
-
- /* Clear (old) imaginary component */
- z.im_sign = 0;
- z.im_exponent = 0;
- for (var i = 0; i < z.im_fraction.length; i++)
- z.im_fraction[i] = 0;
-
+ var z = copy ();
+ var tmp = z.re_num;
+ tmp.clear ();
+ z.re_num = z.im_num;
+ tmp = MPFloat.init2 ((Precision) precision);
+ tmp.set_unsigned_integer (0, Round.NEAREST);
+ z.im_num = tmp;
return z;
}
public Number integer_component ()
{
- /* Clear re_fraction */
- var z = copy ();
- for (var i = z.re_exponent; i < SIZE; i++)
- z.re_fraction[i] = 0;
- z.im_sign = 0;
- z.im_exponent = 0;
- for (var i = 0; i < z.im_fraction.length; i++)
- z.im_fraction[i] = 0;
-
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.trunc (re_num);
+ var z = new Number.mpfloat (tmp);
return z;
}
/* Sets z = x mod 1 */
public Number fractional_component ()
{
- /* fractional component of zero is 0 */
- if (is_zero ())
- return new Number.integer (0);
-
- /* All fractional */
- if (re_exponent <= 0)
- return this;
-
- /* Shift fractional component */
- var shift = re_exponent;
- for (var i = shift; i < SIZE && re_fraction[i] == 0; i++)
- shift++;
- var z = new Number.integer (0);
- z.re_sign = re_sign;
- z.re_exponent = re_exponent - shift;
- for (var i = 0; i < SIZE; i++)
- {
- if (i + shift >= SIZE)
- z.re_fraction[i] = 0;
- else
- z.re_fraction[i] = re_fraction[i + shift];
- }
- if (z.re_fraction[0] == 0)
- z.re_sign = 0;
-
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.frac (re_num, Round.NEAREST);
+ var z = new Number.mpfloat (tmp);
return z;
}
@@ -786,64 +416,28 @@ public class Number : Object
/* Sets z = ⌊x⌋ */
public Number floor ()
{
- /* Integer component of zero = 0 */
- if (is_zero ())
- return this;
-
- /* If all fractional then no integer component */
- if (re_exponent <= 0)
- {
- if (is_negative ())
- return new Number.integer (-1);
- else
- return new Number.integer (0);
- }
-
- /* Clear fractional component */
- var z = copy ();
- var have_fraction = false;
- for (var i = z.re_exponent; i < SIZE; i++)
- {
- if (z.re_fraction[i] != 0)
- have_fraction = true;
- z.re_fraction[i] = 0;
- }
- z.im_sign = 0;
- z.im_exponent = 0;
- for (var i = 0; i < z.im_fraction.length; i++)
- z.im_fraction[i] = 0;
-
- if (have_fraction && is_negative ())
- z = z.add (new Number.integer (-1));
-
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.floor (re_num);
+ var z = new Number.mpfloat (tmp);
return z;
}
/* Sets z = ⌈x⌉ */
public Number ceiling ()
{
- var z = floor ();
- var f = fractional_component ();
- if (f.is_zero ())
- return z;
- return z.add (new Number.integer (1));
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.ceil (re_num);
+ var z = new Number.mpfloat (tmp);
+ return z;
}
/* Sets z = [x] */
public Number round ()
{
- var do_floor = !is_negative ();
-
- var f = fractional_component ();
- f = f.multiply_integer (2);
- f = f.abs ();
- if (f.compare (new Number.integer (1)) >= 0)
- do_floor = !do_floor;
-
- if (do_floor)
- return floor ();
- else
- return ceiling ();
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.round (re_num);
+ var z = new Number.mpfloat (tmp);
+ return z;
}
/* Sets z = 1 ÷ x */
@@ -868,6 +462,7 @@ public class Number : Object
/* Sets z = e^x */
public Number epowy ()
{
+
/* e^0 = 1 */
if (is_zero ())
return new Number.integer (1);
@@ -887,9 +482,23 @@ public class Number : Object
/* Sets z = x^y */
public Number xpowy (Number y)
{
- if (y.is_integer ())
- return xpowy_integer (y.to_integer ());
- else
+ /* 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 (!y.is_integer ())
{
var reciprocal = y.reciprocal ();
if (reciprocal.is_integer ())
@@ -897,6 +506,29 @@ public class Number : Object
else
return pwr (y);
}
+
+ Number t;
+ Number t2;
+ if (y.is_negative ())
+ {
+ t = reciprocal ();
+ t2 = y.invert_sign ();
+ }
+ else
+ {
+ t = this;
+ t2 = y;
+ }
+
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.power (t.re_num, t2.re_num, Round.NEAREST);
+ var z = new Number.mpfloat (tmp);
+ var tmp2 = z.im_num;
+ tmp2.clear ();
+ tmp = MPFloat.init2 ((Precision) precision);
+ tmp set (t.im_num, Round.NEAREST);
+ z.im_num = tmp;
+ return z;
}
/* Sets z = x^y */
@@ -906,7 +538,7 @@ public class Number : Object
if (is_zero () && n < 0)
{
/* Translators: Error displayed when attempted to raise 0 to a negative re_exponent */
- mperr (_("The power of zero is undefined for a negative exponent"));
+ error = _("The power of zero is undefined for a negative exponent");
return new Number.integer (0);
}
@@ -914,22 +546,10 @@ public class Number : Object
if (is_zero () && n == 0)
{
/* Translators: Error displayed when attempted to raise 0 to power of zero */
- mperr (_("Zero raised to zero is undefined"));
+ error = _("Zero raised to zero is undefined");
return new Number.integer (0);
}
- /* x^0 = 1 */
- if (n == 0)
- return new Number.integer (1);
-
- /* 0^n = 0 */
- if (is_zero ())
- return new Number.integer (0);
-
- /* x^1 = x */
- if (n == 1)
- return this;
-
Number t;
if (n < 0)
{
@@ -937,17 +557,44 @@ public class Number : Object
n = -n;
}
else
+ {
t = this;
+ }
- var z = new Number.integer (1);
- while (n != 0)
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.power_signed_integer (t.re_num, (long) n, Round.NEAREST);
+ var z = new Number.mpfloat (tmp);
+ var tmp2 = z.im_num;
+ tmp2.clear ();
+ tmp = MPFloat.init2 ((Precision) precision);
+ tmp set (t.im_num, Round.NEAREST);
+ z.im_num = tmp;
+ return z;
+ }
+
+ private Number pwr (Number y)
+ {
+ /* (-x)^y imaginary */
+ /* FIXME: Make complex numbers optional */
+ /*if (re_sign < 0)
{
- if (n % 2 == 1)
- z = z.multiply (t);
- t = t.multiply (t);
- n = n / 2;
+ mperr (_("The power of negative numbers is only defined for integer exponents"));
+ return new Number.integer (0);
+ }*/
+
+ /* 0^y = 0, 0^-y undefined */
+ if (is_zero ())
+ {
+ if (y.is_negative ())
+ error = _("The power of zero is undefined for a negative exponent");
+ return new Number.integer (0);
}
- return z;
+
+ /* x^0 = 1 */
+ if (y.is_zero ())
+ return new Number.integer (1);
+
+ return y.multiply (ln ()).epowy ();
}
/* Sets z = n√x */
@@ -976,21 +623,10 @@ public class Number : Object
/* Sets z = √x */
public Number sqrt ()
{
- if (is_zero ())
- return this;
-
- /* FIXME: Make complex numbers optional */
- /*if (re_sign < 0)
- {
- mperr (_("Square root is undefined for negative values"));
- return new Number.integer (0);
- }*/
- else
- {
- var t = root (-2);
- var z = multiply (t);
- return z.ext (t.re_fraction[0], z.re_fraction[0]);
- }
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.sqrt (re_num, Round.NEAREST);
+ var z = new Number.mpfloat (tmp);
+ return z;
}
/* Sets z = ln x */
@@ -1000,7 +636,7 @@ public class Number : Object
if (is_zero ())
{
/* Translators: Error displayed when attempting to take logarithm of zero */
- mperr (_("Logarithm of zero is undefined"));
+ error = _("Logarithm of zero is undefined");
return new Number.integer (0);
}
@@ -1033,7 +669,7 @@ public class Number : Object
if (is_zero ())
{
/* Translators: Error displayed when attempting to take logarithm of zero */
- mperr (_("Logarithm of zero is undefined"));
+ error = _("Logarithm of zero is undefined");
return new Number.integer (0);
}
@@ -1052,19 +688,20 @@ public class Number : Object
{
/* Factorial Not defined for Complex or for negative numbers */
- if(is_negative () || is_complex ())
+ if (is_negative () || is_complex ())
{
/* Translators: Error displayed when attempted take the factorial of a negative or complex
number */
- mperr (_("Factorial is only defined for non-negative real numbers"));
+ error = _("Factorial is only defined for non-negative real numbers");
return new Number.integer (0);
}
- var val = to_double ();
+ var tmp = add (new Number.integer (1));
+ var tmp2 = MPFloat.init2 ((Precision) precision);
/* Factorial(x) = Gamma(x+1) - This is the formula used to calculate Factorial.*/
- var fact = Math.tgamma(val+1);
+ tmp2.gamma (tmp.re_num, Round.NEAREST);
- return new Number.double(fact);
+ return new Number.mpfloat (tmp2);
}
/* Convert to integer - if couldn't be converted then the factorial would be too big anyway */
@@ -1079,23 +716,41 @@ public class Number : Object
/* Sets z = x + y */
public Number add (Number y)
{
- return add_with_sign (1, y);
+ if (is_complex () || y.is_complex ())
+ {
+ Number real_z, im_z;
+
+ var real_x = real_component ();
+ var im_x = imaginary_component ();
+ var real_y = y.real_component ();
+ var im_y = y.imaginary_component ();
+
+ real_z = real_x.add_real (real_y);
+ im_z = im_x.add_real (im_y);
+
+ return new Number.complex (real_z, im_z);
+ }
+ else
+ return add_real (y);
+ }
+
+ public Number add_real (Number y)
+ {
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.add (re_num, y.re_num, Round.NEAREST);
+ var z = new Number.mpfloat (tmp);
+ return z;
}
/* Sets z = x − y */
public Number subtract (Number y)
{
- return add_with_sign (-1, y);
+ return add (y.invert_sign ());
}
/* Sets z = x × y */
public Number multiply (Number y)
{
- /* x*0 = 0*y = 0 */
- if (is_zero () || y.is_zero ())
- return new Number.integer (0);
-
- /* (a+bi)(c+di) = (ac-bd)+(ad+bc)i */
if (is_complex () || y.is_complex ())
{
Number t1, t2, real_z, im_z;
@@ -1119,58 +774,63 @@ public class Number : Object
return multiply_real (y);
}
+ public Number multiply_real (Number y)
+ {
+ var z = new Number.integer (0);
+ var tmp = z.re_num;
+ tmp.multiply (re_num, y.re_num, Round.NEAREST);
+ z.re_num = tmp;
+ return z;
+ }
+
/* Sets z = x × y */
public Number multiply_integer (int64 y)
{
- if (is_complex ())
- {
- var re_z = real_component ().multiply_integer_real (y);;
- var im_z = imaginary_component ().multiply_integer_real (y);
- return new Number.complex (re_z, im_z);
- }
- else
- return multiply_integer_real (y);
+ var z = new Number.integer (0);
+ var tmp = z.re_num;
+ tmp.multiply_signed_integer (re_num, (long) y, Round.NEAREST);
+ z.re_num = tmp;
+ return z;
}
/* Sets z = x ÷ y */
public Number divide (Number y)
{
- /* x/0 */
if (y.is_zero ())
{
/* Translators: Error displayed attempted to divide by zero */
- mperr (_("Division by zero is undefined"));
+ error = _("Division by zero is undefined");
return new Number.integer (0);
}
- /* 0/y = 0 */
- if (is_zero ())
- return this;
+ if (is_complex () || y.is_complex ())
+ {
+ var a = real_component ();
+ var b = imaginary_component ();
+ var c = y.real_component ();
+ var d = y.imaginary_component ();
+
+ var tmp = a.multiply (c).add (b.multiply (d));
+ var tmp_2 = c.xpowy_integer (2).add (d.xpowy_integer (2));
+ var z_1 = tmp.divide (tmp_2);
- /* z = x × y⁻¹ */
- /* FIXME: Set re_exponent to zero to avoid overflow in multiply??? */
- var t = y.reciprocal ();
- var ie = t.re_exponent;
- t.re_exponent = 0;
- var i = t.re_fraction[0];
- var z = multiply (t);
- z = z.ext (i, z.re_fraction[0]);
- z.re_exponent += ie;
+ tmp = b.multiply (c).subtract (a.multiply (d));
+ var z_2 = tmp.divide (tmp_2);
+ var z = new Number.complex (z_1, z_2);
+ return z;
+ }
+
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.divide (re_num, y.re_num, Round.NEAREST);
+ var z = new Number.mpfloat (tmp);
return z;
}
/* Sets z = x ÷ y */
public Number divide_integer (int64 y)
{
- if (is_complex ())
- {
- var re_z = real_component ().divide_integer_real (y);
- var im_z = imaginary_component ().divide_integer_real (y);
- return new Number.complex (re_z, im_z);
- }
- else
- return divide_integer_real (y);
+ return divide (new Number.integer (y));
}
/* Sets z = x mod y */
@@ -1179,7 +839,7 @@ public class Number : Object
if (!is_integer () || !y.is_integer ())
{
/* Translators: Error displayed when attemping to do a modulus division on non-integer numbers */
- mperr (_("Modulus division is only defined for integers"));
+ error = _("Modulus division is only defined for integers");
return new Number.integer (0);
}
@@ -1197,7 +857,7 @@ public class Number : Object
/* Sets z = x ^ y mod p */
public Number modular_exponentiation (Number exp, Number mod)
{
- var base_value = this.copy ();
+ var base_value = copy ();
if (exp.is_negative ())
base_value = base_value.reciprocal ();
var exp_value = exp.abs ();
@@ -1267,250 +927,97 @@ public class Number : Object
public Number tan (AngleUnit unit = AngleUnit.RADIANS)
{
/* Check for undefined values */
- var cos_x = cos (unit);
- if (cos_x.is_zero ())
+ 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 */
- mperr (_("Tangent is undefined for angles that are multiples of π (180°) from π∕2 (90°)"));
+ error = _("Tangent is undefined for angles that are multiples of π (180°) from π∕2 (90°)");
return new Number.integer (0);
}
- /* tan (x) = sin (x) / cos (x) */
- return sin (unit).divide (cos_x);
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.tan (x_radians.re_num, Round.NEAREST);
+ var z = new Number.mpfloat (tmp);
+ return z;
}
/* Sets z = sin⁻¹ x */
public Number asin (AngleUnit unit = AngleUnit.RADIANS)
{
- /* asin⁻¹(0) = 0 */
- if (is_zero ())
- return new Number.integer (0);
-
- /* sin⁻¹(x) = tan⁻¹(x / √(1 - x²)), |x| < 1 */
- if (re_exponent <= 0)
- {
- var t1 = new Number.integer (1);
- var t2 = t1;
- t1 = t1.subtract (this);
- t2 = t2.add (this);
- t2 = t1.multiply (t2);
- t2 = t2.root (-2);
- var z = multiply (t2);
- z = z.atan (unit);
- return z;
- }
-
- /* sin⁻¹(1) = π/2, sin⁻¹(-1) = -π/2 */
- var t2 = new Number.integer (re_sign);
- if (equals (t2))
+ if (compare (new Number.integer (1)) > 0 || compare (new Number.integer (-1)) < 0)
{
- var z = new Number.pi ().divide_integer (2 * t2.re_sign);
- return z.from_radians (unit);
+ /* Translators: Error displayed when inverse sine value is undefined */
+ error = _("Inverse sine is undefined for values outside [-1, 1]");
+ return new Number.integer (0);
}
- /* Translators: Error displayed when inverse sine value is undefined */
- mperr (_("Inverse sine is undefined for values outside [-1, 1]"));
- return new Number.integer (0);
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.asin (re_num, Round.NEAREST);
+ var z = new Number.mpfloat (tmp);
+ return z.from_radians (unit);
}
/* Sets z = cos⁻¹ x */
public Number acos (AngleUnit unit = AngleUnit.RADIANS)
{
- var pi = new Number.pi ();
- var t1 = new Number.integer (1);
- var n1 = new Number.integer (-1);
-
- Number z;
- if (compare (t1) > 0 || compare (n1) < 0)
+ if (compare (new Number.integer (1)) > 0 || compare (new Number.integer (-1)) < 0)
{
/* Translators: Error displayed when inverse cosine value is undefined */
- mperr (_("Inverse cosine is undefined for values outside [-1, 1]"));
- z = new Number.integer (0);
- }
- else if (is_zero ())
- z = pi.divide_integer (2);
- else if (equals (t1))
- z = new Number.integer (0);
- else if (equals (n1))
- z = pi;
- else
- {
- /* cos⁻¹(x) = tan⁻¹(√(1 - x²) / x) */
- Number y;
- var t2 = multiply (this);
- t2 = t1.subtract (t2);
- t2 = t2.sqrt ();
- t2 = t2.divide (this);
- y = t2.atan (AngleUnit.RADIANS);
- if (re_sign > 0)
- z = y;
- else
- z = y.add (pi);
+ error = _("Inverse cosine is undefined for values outside [-1, 1]");
+ return new Number.integer (0);
}
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.acos (re_num, Round.NEAREST);
+ var z = new Number.mpfloat (tmp);
return z.from_radians (unit);
}
/* Sets z = tan⁻¹ x */
public Number atan (AngleUnit unit = AngleUnit.RADIANS)
{
- if (is_zero ())
- return new Number.integer (0);
-
- var t2 = this;
- var rx = 0f;
- if (re_exponent.abs () <= 2)
- rx = to_float ();
-
- /* REDUCE ARGUMENT IF NECESSARY BEFORE USING SERIES */
- var q = 1;
- Number z;
- while (t2.re_exponent >= 0)
- {
- if (t2.re_exponent == 0 && 2 * (t2.re_fraction[0] + 1) <= BASE)
- break;
-
- q *= 2;
-
- /* t = t / (√(t² + 1) + 1) */
- z = t2.multiply (t2);
- z = z.add (new Number.integer (1));
- z = z.sqrt ();
- z = z.add (new Number.integer (1));
- t2 = t2.divide (z);
- }
-
- /* USE POWER SERIES NOW ARGUMENT IN (-0.5, 0.5) */
- z = t2;
- var t1 = t2.multiply (t2);
-
- /* SERIES LOOP. REDUCE T IF POSSIBLE. */
- for (var i = 1; ; i += 2)
- {
- if (T + 2 + t2.re_exponent <= 1)
- break;
-
- t2 = t2.multiply (t1).multiply_integer (-i).divide_integer (i + 2);
-
- z = z.add (t2);
- if (t2.is_zero ())
- break;
- }
-
- /* CORRECT FOR ARGUMENT REDUCTION */
- z = z.multiply_integer (q);
-
- /* CHECK THAT RELATIVE ERROR LESS THAN 0.01 UNLESS re_exponent
- * OF X IS LARGE (WHEN ATAN MIGHT NOT WORK)
- */
- if (re_exponent.abs () <= 2)
- {
- float ry = z.to_float ();
- /* THE FOLLOWING MESSAGE MAY INDICATE THAT B**(T-1) IS TOO SMALL. */
- if (Math.fabs (ry - Math.atan (rx)) >= Math.fabs (ry) * 0.01)
- mperr ("*** ERROR OCCURRED IN ATAN, RESULT INCORRECT ***");
- }
-
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.atan (re_num, Round.NEAREST);
+ var z = new Number.mpfloat (tmp);
return z.from_radians (unit);
}
/* Sets z = sinh x */
public Number sinh ()
{
- /* sinh (0) = 0 */
- if (is_zero ())
- return new Number.integer (0);
-
- /* WORK WITH ABS (X) */
- var abs_x = abs ();
-
- /* If |x| < 1 USE EXP TO AVOID CANCELLATION, otherwise IF TOO LARGE EPOWY GIVES ERROR MESSAGE */
- Number z;
- if (abs_x.re_exponent <= 0)
- {
- /* ((e^|x| + 1) * (e^|x| - 1)) / e^|x| */
- // FIXME: Solves to e^|x| - e^-|x|, why not lower branch always? */
- var exp_x = abs_x.epowy ();
- var a = exp_x.add (new Number.integer (1));
- var b = exp_x.add (new Number.integer (-1));
- z = a.multiply (b);
- z = z.divide (exp_x);
- }
- else
- {
- /* e^|x| - e^-|x| */
- var exp_x = abs_x.epowy ();
- z = exp_x.reciprocal ();
- z = exp_x.subtract (z);
- }
-
- /* DIVIDE BY TWO AND RESTORE re_sign */
- z = z.divide_integer (2);
- return z.multiply_integer (re_sign);
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.sinh (re_num, Round.NEAREST);
+ var z = new Number.mpfloat (tmp);
+ return z;
}
/* Sets z = cosh x */
public Number cosh ()
{
- /* cosh (0) = 1 */
- if (is_zero ())
- return new Number.integer (1);
-
- /* cosh (x) = (e^x + e^-x) / 2 */
- var t = abs ();
- t = t.epowy ();
- var z = t.reciprocal ();
- z = t.add (z);
- return z.divide_integer (2);
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.cosh (re_num, Round.NEAREST);
+ var z = new Number.mpfloat (tmp);
+ return z;
}
/* Sets z = tanh x */
public Number tanh ()
{
- /* tanh (0) = 0 */
- if (is_zero ())
- return new Number.integer (0);
-
- var t = abs ();
-
- /* SEE IF ABS (X) SO LARGE THAT RESULT IS +-1 */
- var r__1 = (float) T * 0.5 * Math.log ((float) BASE);
- var z = new Number.double (r__1);
- if (t.compare (z) > 0)
- return new Number.integer (re_sign);
-
- /* If |x| >= 1/2 use ?, otherwise use ? to avoid cancellation */
- /* |tanh (x)| = (e^|2x| - 1) / (e^|2x| + 1) */
- t = t.multiply_integer (2);
- if (t.re_exponent > 0)
- {
- t = t.epowy ();
- z = t.add (new Number.integer (-1));
- t = t.add (new Number.integer (1));
- z = z.divide (t);
- }
- else
- {
- t = t.epowy ();
- z = t.add (new Number.integer (1));
- t = t.add (new Number.integer (-1));
- z = t.divide (z);
- }
-
- /* Restore re_sign */
- z.re_sign = re_sign * z.re_sign;
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.tanh (re_num, Round.NEAREST);
+ var z = new Number.mpfloat (tmp);
return z;
}
/* Sets z = sinh⁻¹ x */
public Number asinh ()
{
- /* sinh⁻¹(x) = ln (x + √(x² + 1)) */
- var t = multiply (this);
- t = t.add (new Number.integer (1));
- t = t.sqrt ();
- t = add (t);
- return t.ln ();
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.asinh (re_num, Round.NEAREST);
+ var z = new Number.mpfloat (tmp);
+ return z;
}
/* Sets z = cosh⁻¹ x */
@@ -1521,16 +1028,14 @@ public class Number : Object
if (compare (t) < 0)
{
/* Translators: Error displayed when inverse hyperbolic cosine value is undefined */
- mperr (_("Inverse hyperbolic cosine is undefined for values less than one"));
+ error = _("Inverse hyperbolic cosine is undefined for values less than one");
return new Number.integer (0);
}
- /* cosh⁻¹(x) = ln (x + √(x² - 1)) */
- t = multiply (this);
- t = t.add (new Number.integer (-1));
- t = t.sqrt ();
- t = add (t);
- return t.ln ();
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.acosh (re_num, Round.NEAREST);
+ var z = new Number.mpfloat (tmp);
+ return z;
}
/* Sets z = tanh⁻¹ x */
@@ -1540,26 +1045,24 @@ public class Number : Object
if (compare (new Number.integer (1)) >= 0 || compare (new Number.integer (-1)) <= 0)
{
/* Translators: Error displayed when inverse hyperbolic tangent value is undefined */
- mperr (_("Inverse hyperbolic tangent is undefined for values outside [-1, 1]"));
+ error = _("Inverse hyperbolic tangent is undefined for values outside [-1, 1]");
return new Number.integer (0);
}
- /* atanh (x) = 0.5 * ln ((1 + x) / (1 - x)) */
- var n = add (new Number.integer (1));
- var d = invert_sign ();
- d = d.add (new Number.integer (1));
- var z = n.divide (d);
- z = z.ln ();
- return z.divide_integer (2);
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.atanh (re_num, Round.NEAREST);
+ var z = new Number.mpfloat (tmp);
+ 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 ())
+ if (!
+ is_positive_integer () || !y.is_positive_integer ())
{
/* Translators: Error displayed when boolean AND attempted on non-integer values */
- mperr (_("Boolean AND is only defined for positive integers"));
+ error = _("Boolean AND is only defined for positive integers");
}
return bitwise (y, (v1, v2) => { return v1 & v2; }, 0);
@@ -1571,7 +1074,7 @@ public class Number : Object
if (!is_positive_integer () || !y.is_positive_integer ())
{
/* Translators: Error displayed when boolean OR attempted on non-integer values */
- mperr (_("Boolean OR is only defined for positive integers"));
+ error = _("Boolean OR is only defined for positive integers");
}
return bitwise (y, (v1, v2) => { return v1 | v2; }, 0);
@@ -1583,7 +1086,7 @@ public class Number : Object
if (!is_positive_integer () || !y.is_positive_integer ())
{
/* Translators: Error displayed when boolean XOR attempted on non-integer values */
- mperr (_("Boolean XOR is only defined for positive integers"));
+ error = _("Boolean XOR is only defined for positive integers");
}
return bitwise (y, (v1, v2) => { return v1 ^ v2; }, 0);
@@ -1595,7 +1098,7 @@ public class Number : Object
if (!is_positive_integer ())
{
/* Translators: Error displayed when boolean XOR attempted on non-integer values */
- mperr (_("Boolean NOT is only defined for positive integers"));
+ error = _("Boolean NOT is only defined for positive integers");
}
return bitwise (new Number.integer (0), (v1, v2) => { return v1 ^ 0xF; }, wordlen);
@@ -1618,7 +1121,7 @@ public class Number : Object
if (!is_integer ())
{
/* Translators: Error displayed when bit shift attempted on non-integer values */
- mperr (_("Shift is only possible on integer values"));
+ error = _("Shift is only possible on integer values");
return new Number.integer (0);
}
@@ -1750,834 +1253,38 @@ public class Number : Object
private Number copy ()
{
var z = new Number ();
- z.re_sign = re_sign;
- z.im_sign = im_sign;
- z.re_exponent = re_exponent;
- z.im_exponent = im_exponent;
- for (var i = 0; i < re_fraction.length; i++)
- {
- z.re_fraction[i] = re_fraction[i];
- z.im_fraction[i] = im_fraction[i];
- }
-
+ var tmp = MPFloat.init2 ((Precision) precision);
+ var tmp2 = MPFloat.init2 ((Precision) precision);
+ tmp set(re_num, Round.NEAREST);
+ tmp2 set(im_num, Round.NEAREST);
+ z.re_num = tmp;
+ z.im_num = tmp2;
return z;
}
- private Number add_with_sign (int y_sign, Number y)
- {
- if (is_complex () || y.is_complex ())
- {
- Number real_z, im_z;
-
- var real_x = real_component ();
- var im_x = imaginary_component ();
- var real_y = y.real_component ();
- var im_y = y.imaginary_component ();
-
- real_z = real_x.add_real (y_sign * y.re_sign, real_y);
- im_z = im_x.add_real (y_sign * y.im_sign, im_y);
-
- return new Number.complex (real_z, im_z);
- }
- else
- return add_real (y_sign * y.re_sign, y);
- }
-
private Number epowy_real ()
{
- /* e^0 = 1 */
- if (is_zero ())
- return new Number.integer (1);
-
- /* If |x| < 1 use exp */
- if (re_exponent <= 0)
- return exp ();
-
- /* NOW SAFE TO CONVERT X TO REAL */
- var rx = to_double ();
-
- /* SAVE re_sign AND WORK WITH ABS (X) */
- var xs = re_sign;
- var t2 = abs ();
-
- /* GET fractional AND INTEGER PARTS OF ABS (X) */
- var ix = t2.to_integer ();
- t2 = t2.fractional_component ();
-
- /* ATTACH re_sign TO fractional PART AND COMPUTE EXP OF IT */
- t2.re_sign *= xs;
- var z = t2.exp ();
-
- /* COMPUTE E-2 OR 1/E USING TWO EXTRA DIGITS IN CASE ABS (X) LARGE
- * (BUT ONLY ONE EXTRA DIGIT IF T < 4)
- */
- var tss = 0;
- if (T < 4)
- tss = T + 1;
- else
- tss = T + 2;
-
- /* LOOP FOR E COMPUTATION. DECREASE T IF POSSIBLE. */
- /* Computing MIN */
- var t1 = new Number.integer (xs);
-
- t2.re_sign = 0;
- for (var i = 2 ; ; i++)
- {
- if (int.min (tss, tss + 2 + t1.re_exponent) <= 2)
- break;
-
- t1 = t1.divide_integer (i * xs);
- t2 = t2.add (t1);
- if (t1.is_zero ())
- break;
- }
-
- /* RAISE E OR 1/E TO POWER IX */
- if (xs > 0)
- t2 = t2.add (new Number.integer (2));
- t2 = t2.xpowy_integer (ix);
-
- /* MULTIPLY EXPS OF INTEGER AND fractional PARTS */
- z = z.multiply (t2);
-
- /* CHECK THAT RELATIVE ERROR LESS THAN 0.01 UNLESS ABS (X) LARGE
- * (WHEN EXP MIGHT OVERFLOW OR UNDERFLOW)
- */
- if (Math.fabs (rx) > 10.0f)
- return z;
-
- var rz = z.to_double ();
- var r__1 = rz - Math.exp (rx);
- if (Math.fabs (r__1) < rz * 0.01f)
- return z;
-
- /* THE FOLLOWING MESSAGE MAY INDICATE THAT
- * B**(T-1) IS TOO SMALL, OR THAT M IS TOO SMALL SO THE
- * RESULT UNDERFLOWED.
- */
- mperr ("*** ERROR OCCURRED IN EPOWY, RESULT INCORRECT ***");
+ var z = copy ();
+ var tmp = z.re_num;
+ tmp.exp (re_num, Round.NEAREST);
+ z.re_num = tmp;
return z;
}
- /* Return e^x for |x| < 1 USING AN o (SQRt (T).m (T)) ALGORITHM
- * DESCRIBED IN - R. P. BRENT, THE COMPLEXITY OF MULTIPLE-
- * PRECISION ARITHMETIC (IN COMPLEXITY OF COMPUTATIONAL PROBLEM
- * SOLVING, UNIV. OF QUEENSLAND PRESS, BRISBANE, 1976, 126-165).
- * ASYMPTOTICALLY FASTER METHODS EXIST, BUT ARE NOT USEFUL
- * UNLESS T IS VERY LARGE. SEE COMMENTS TO MP_ATAN AND MPPIGL.
- */
- private Number exp ()
- {
- /* e^0 = 1 */
- if (is_zero ())
- return new Number.integer (1);
-
- /* Only defined for |x| < 1 */
- if (re_exponent > 0)
- {
- mperr ("*** ABS (X) NOT LESS THAN 1 IN CALL TO MP_EXP ***");
- return new Number.integer (0);
- }
-
- var t1 = this;
- var rlb = Math.log (BASE);
-
- /* Compute approximately optimal q (and divide x by 2^q) */
- var q = (int) (Math.sqrt (T * 0.48 * rlb) + re_exponent * 1.44 * rlb);
-
- /* HALVE Q TIMES */
- if (q > 0)
- {
- var ib = BASE << 2;
- var ic = 1;
- for (var i = 1; i <= q; i++)
- {
- ic *= 2;
- if (ic < ib && ic != BASE && i < q)
- continue;
- t1 = t1.divide_integer (ic);
- ic = 1;
- }
- }
-
- if (t1.is_zero ())
- return new Number.integer (0);
-
- /* Sum series, reducing t where possible */
- var z = t1.copy ();
- var t2 = t1;
- for (var i = 2; T + t2.re_exponent - z.re_exponent > 0; i++)
- {
- t2 = t1.multiply (t2);
- t2 = t2.divide_integer (i);
- z = t2.add (z);
- if (t2.is_zero ())
- break;
- }
-
- /* Apply (x+1)^2 - 1 = x (2 + x) for q iterations */
- for (var i = 1; i <= q; i++)
- {
- t1 = z.add (new Number.integer (2));
- z = t1.multiply (z);
- }
-
- return z.add (new Number.integer (1));
- }
-
- private Number pwr (Number y)
- {
- /* (-x)^y imaginary */
- /* FIXME: Make complex numbers optional */
- /*if (re_sign < 0)
- {
- mperr (_("The power of negative numbers is only defined for integer exponents"));
- return new Number.integer (0);
- }*/
-
- /* 0^y = 0, 0^-y undefined */
- if (is_zero ())
- {
- if (y.re_sign < 0)
- mperr (_("The power of zero is undefined for a negative exponent"));
- return new Number.integer (0);
- }
-
- /* x^0 = 1 */
- if (y.is_zero ())
- return new Number.integer (1);
-
- return y.multiply (ln ()).epowy ();
- }
-
private Number root_real (int64 n)
{
- /* x^(1/1) = x */
- if (n == 1)
- return this;
-
- /* x^(1/0) invalid */
- if (n == 0)
- {
- mperr (_("Root must be non-zero"));
- return new Number.integer (0);
- }
-
- var np = n.abs ();
-
- /* LOSS OF ACCURACY IF NP LARGE, SO ONLY ALLOW NP <= MAX (B, 64) */
- if (np > int.max (BASE, 64))
- {
- mperr ("*** ABS (N) TOO LARGE IN CALL TO ROOT ***");
- return new Number.integer (0);
- }
-
- /* 0^(1/n) = 0 for positive n */
- if (is_zero ())
- {
- if (n <= 0)
- mperr (_("Negative root of zero is undefined"));
- return new Number.integer (0);
- }
-
- // FIXME: Imaginary root
- if (re_sign < 0 && np % 2 == 0)
- {
- mperr (_("nth root of negative number is undefined for even n"));
- return new Number.integer (0);
- }
-
- /* DIVIDE re_exponent BY NP */
- var ex = re_exponent / np;
-
- /* Get initial approximation */
- var t1 = copy ();
- t1.re_exponent = 0;
- var approximation = Math.exp (((np * ex - re_exponent) * Math.log (BASE) - Math.log (Math.fabs
(t1.to_float ()))) / np);
- t1 = new Number.double (approximation);
- t1.re_sign = re_sign;
- t1.re_exponent -= (int) ex;
-
- /* MAIN ITERATION LOOP */
- var it0 = 3;
- var t = it0;
- Number t2;
- while (true)
- {
- /* t1 = t1 - ((t1 * ((x * t1^np) - 1)) / np) */
- t2 = t1.xpowy_integer (np);
- t2 = multiply (t2);
- t2 = t2.add (new Number.integer (-1));
- t2 = t1.multiply (t2);
- t2 = t2.divide_integer (np);
- t1 = t1.subtract (t2);
-
- /* FOLLOWING LOOP ALMOST DOUBLES T (POSSIBLE BECAUSE
- * NEWTONS METHOD HAS 2ND ORDER CONVERGENCE).
- */
- if (t >= T)
- break;
-
- var ts3 = t;
- var ts2 = t;
- t = T;
- do
- {
- ts2 = t;
- t = (t + it0) / 2;
- } while (t > ts3);
- t = int.min (ts2, T);
- }
-
- /* NOW r (I2) IS X**(-1/NP)
- * CHECK THAT NEWTON ITERATION WAS CONVERGING
- */
- if (t2.re_sign != 0 && (t1.re_exponent - t2.re_exponent) << 1 < T - it0)
- {
- /* THE FOLLOWING MESSAGE MAY INDICATE THAT B**(T-1) IS TOO SMALL,
- * OR THAT THE INITIAL APPROXIMATION OBTAINED USING ALOG AND EXP
- * IS NOT ACCURATE ENOUGH.
- */
- mperr ("*** ERROR OCCURRED IN ROOT, NEWTON ITERATION NOT CONVERGING PROPERLY ***");
- }
-
- if (n >= 0)
- {
- t1 = t1.xpowy_integer (n - 1);
- return multiply (t1);
- }
-
- return t1;
- }
-
- /* ROUTINE CALLED BY DIVIDE AND SQRT TO ENSURE THAT
- * RESULTS ARE REPRESENTED EXACTLY IN T-2 DIGITS IF THEY
- * CAN BE. X IS AN MP NUMBER, I AND J ARE INTEGERS.
- */
- private Number ext (int i, int j)
- {
- if (is_zero () || T <= 2 || i == 0)
- return this;
-
- /* COMPUTE MAXIMUM POSSIBLE ERROR IN THE LAST PLACE */
- var q = (j + 1) / i + 1;
- var s = BASE * re_fraction[T - 2] + re_fraction[T - 1];
-
- /* SET LAST TWO DIGITS TO ZERO */
var z = copy ();
- if (s <= q)
- {
- z.re_fraction[T - 2] = 0;
- z.re_fraction[T - 1] = 0;
- return z;
- }
-
- if (s + q < BASE * BASE)
- return z;
-
- /* ROUND UP HERE */
- z.re_fraction[T - 2] = BASE - 1;
- z.re_fraction[T - 1] = BASE;
-
- /* NORMALIZE X (LAST DIGIT B IS OK IN MULTIPLY_INTEGER) */
- return z.multiply_integer (1);
- }
-
- private Number ln_real ()
- {
- // ln(e^1) = 1, fixes precision loss
- if (equals (new Number.eulers ()))
- return new Number.integer (1);
-
- /* LOOP TO GET APPROXIMATE Ln (X) USING SINGLE-PRECISION */
- var t1 = copy ();
- var z = new Number.integer (0);
- for (var k = 0; k < 10; k++)
- {
- /* COMPUTE FINAL CORRECTION ACCURATELY USING LNS */
- var t2 = t1.add (new Number.integer (-1));
- if (t2.is_zero () || t2.re_exponent + 1 <= 0)
- return z.add (t2.lns ());
-
- /* REMOVE EXPONENT TO AVOID FLOATING-POINT OVERFLOW */
- var e = t1.re_exponent;
- t1.re_exponent = 0;
- var rx = t1.to_double ();
- t1.re_exponent = e;
- var rlx = Math.log (rx) + e * Math.log (BASE);
- t2 = new Number.double (-rlx);
-
- /* UPDATE Z AND COMPUTE ACCURATE EXP OF APPROXIMATE LOG */
- z = z.subtract (t2);
- t2 = t2.epowy ();
-
- /* COMPUTE RESIDUAL WHOSE LOG IS STILL TO BE FOUND */
- t1 = t1.multiply (t2);
- }
-
- mperr ("*** ERROR IN LN, ITERATION NOT CONVERGING ***");
- return z;
- }
-
- /* RETURNS MP Y = Ln (1+X) IF X IS AN MP NUMBER SATISFYING THE
- * CONDITION ABS (X) < 1/B, ERROR OTHERWISE.
- * USES NEWTONS METHOD TO SOLVE THE EQUATION
- * EXP1(-Y) = X, THEN REVERSES re_sign OF Y.
- */
- private Number lns ()
- {
- /* ln (1+0) = 0 */
- if (is_zero ())
- return this;
-
- /* Get starting approximation -ln (1+x) ~= -x + x^2/2 - x^3/3 + x^4/4 */
- var t2 = copy ();
- var t1 = divide_integer (4);
- t1 = t1.add (new Number.fraction (-1, 3));
- t1 = multiply (t1);
- t1 = t1.add (new Number.fraction (1, 2));
- t1 = multiply (t1);
- t1 = t1.add (new Number.integer (-1));
- var z = multiply (t1);
-
- /* Solve using Newtons method */
- var it0 = 5;
- var t = it0;
- Number t3;
- while (true)
- {
- /* t3 = (e^t3 - 1) */
- /* z = z - (t2 + t3 + (t2 * t3)) */
- t3 = z.epowy ();
- t3 = t3.add (new Number.integer (-1));
- t1 = t2.multiply (t3);
- t3 = t3.add (t1);
- t3 = t2.add (t3);
- z = z.subtract (t3);
- if (t >= T)
- break;
-
- /* FOLLOWING LOOP COMPUTES NEXT VALUE OF T TO USE.
- * BECAUSE NEWTONS METHOD HAS 2ND ORDER CONVERGENCE,
- * WE CAN ALMOST DOUBLE T EACH TIME.
- */
- var ts3 = t;
- var ts2 = t;
- t = T;
- do
- {
- ts2 = t;
- t = (t + it0) / 2;
- } while (t > ts3);
- t = ts2;
- }
-
- /* CHECK THAT NEWTON ITERATION WAS CONVERGING AS EXPECTED */
- if (t3.re_sign != 0 && t3.re_exponent << 1 > it0 - T)
- mperr ("*** ERROR OCCURRED IN LNS, NEWTON ITERATION NOT CONVERGING PROPERLY ***");
-
- z.re_sign = -z.re_sign;
-
- return z;
- }
-
- private Number add_real (int y_sign, Number y)
- {
- var re_sign_prod = y_sign * re_sign;
-
- /* 0 + y = y */
- if (is_zero ())
- {
- if (y_sign != y.re_sign)
- return y.invert_sign ();
- else
- return y;
- }
- /* x + 0 = x */
- else if (y.is_zero ())
- return this;
-
- var exp_diff = re_exponent - y.re_exponent;
- var med = exp_diff.abs ();
- var x_largest = false;
- if (exp_diff < 0)
- x_largest = false;
- else if (exp_diff > 0)
- x_largest = true;
- else
- {
- /* EXPONENTS EQUAL SO COMPARE SIGNS, THEN FRACTIONS IF NEC. */
- if (re_sign_prod < 0)
- {
- /* signs are not equal. find out which mantissa is larger. */
- int j;
- for (j = 0; j < T; j++)
- {
- int i = re_fraction[j] - y.re_fraction[j];
- if (i != 0)
- {
- if (i < 0)
- x_largest = false;
- else if (i > 0)
- x_largest = true;
- break;
- }
- }
-
- /* Both mantissas equal, so result is zero. */
- if (j >= T)
- return new Number.integer (0);
- }
- }
-
- var z = new Number.integer (0);
-
- int[] big_fraction, small_fraction;
- if (x_largest)
- {
- z.re_sign = re_sign;
- z.re_exponent = re_exponent;
- big_fraction = re_fraction;
- small_fraction = y.re_fraction;
- }
- else
- {
- z.re_sign = y_sign;
- z.re_exponent = y.re_exponent;
- big_fraction = y.re_fraction;
- small_fraction = re_fraction;
- }
-
- /* CLEAR GUARD DIGITS TO RIGHT OF X DIGITS */
- for (var i = 3; i >= med; i--)
- z.re_fraction[T + i] = 0;
-
- if (re_sign_prod >= 0)
- {
- /* This is probably insufficient overflow detection, but it makes us not crash at least. */
- if (T + 3 < med)
- {
- mperr (_("Overflow: the result couldn't be calculated"));
- return new Number.integer (0);
- }
-
- /* HERE DO ADDITION, re_exponent (Y) >= re_exponent (X) */
- var i = 0;
- for (i = T + 3; i >= T; i--)
- z.re_fraction[i] = small_fraction[i - med];
-
- var c = 0;
- for (; i >= med; i--)
- {
- c = big_fraction[i] + small_fraction[i - med] + c;
-
- if (c < BASE)
- {
- /* NO CARRY GENERATED HERE */
- z.re_fraction[i] = c;
- c = 0;
- }
- else
- {
- /* CARRY GENERATED HERE */
- z.re_fraction[i] = c - BASE;
- c = 1;
- }
- }
-
- for (; i >= 0; i--)
- {
- c = big_fraction[i] + c;
- if (c < BASE)
- {
- z.re_fraction[i] = c;
- i--;
-
- /* NO CARRY POSSIBLE HERE */
- for (; i >= 0; i--)
- z.re_fraction[i] = big_fraction[i];
-
- c = 0;
- break;
- }
-
- z.re_fraction[i] = 0;
- c = 1;
- }
-
- /* MUST SHIFT RIGHT HERE AS CARRY OFF END */
- if (c != 0)
- {
- for (var j = T + 3; j > 0; j--)
- z.re_fraction[j] = z.re_fraction[j - 1];
- z.re_fraction[0] = 1;
- z.re_exponent++;
- }
- }
- else
- {
- var c = 0;
- var i = 0;
- for (i = T + med - 1; i >= T; i--)
- {
- /* HERE DO SUBTRACTION, ABS (Y) > ABS (X) */
- z.re_fraction[i] = c - small_fraction[i - med];
- c = 0;
-
- /* BORROW GENERATED HERE */
- if (z.re_fraction[i] < 0)
- {
- c = -1;
- z.re_fraction[i] += BASE;
- }
- }
-
- for (; i >= med; i--)
- {
- c = big_fraction[i] + c - small_fraction[i - med];
- if (c >= 0)
- {
- /* NO BORROW GENERATED HERE */
- z.re_fraction[i] = c;
- c = 0;
- }
- else
- {
- /* BORROW GENERATED HERE */
- z.re_fraction[i] = c + BASE;
- c = -1;
- }
- }
-
- for (; i >= 0; i--)
- {
- c = big_fraction[i] + c;
-
- if (c >= 0)
- {
- z.re_fraction[i] = c;
- i--;
-
- /* NO CARRY POSSIBLE HERE */
- for (; i >= 0; i--)
- z.re_fraction[i] = big_fraction[i];
-
- break;
- }
-
- z.re_fraction[i] = c + BASE;
- c = -1;
- }
- }
-
- mp_normalize (ref z);
-
- return z;
- }
-
- private Number multiply_real (Number y)
- {
- /* x*0 = 0*y = 0 */
- if (re_sign == 0 || y.re_sign == 0)
- return new Number.integer (0);
-
- var z = new Number.integer (0);
- z.re_sign = re_sign * y.re_sign;
- z.re_exponent = re_exponent + y.re_exponent;
-
- var r = new Number.integer (0);
-
- /* PERFORM MULTIPLICATION */
- var c = 8;
- for (var i = 0; i < T; i++)
- {
- var xi = re_fraction[i];
-
- /* FOR SPEED, PUT THE NUMBER WITH MANY ZEROS FIRST */
- if (xi == 0)
- continue;
-
- /* Computing MIN */
- for (var j = 0; j < int.min (T, T + 3 - i); j++)
- r.re_fraction[i+j+1] += xi * y.re_fraction[j];
- c--;
- if (c > 0)
- continue;
-
- /* CHECK FOR LEGAL BASE B DIGIT */
- if (xi < 0 || xi >= BASE)
- {
- mperr ("*** ILLEGAL BASE B DIGIT IN CALL TO MULTIPLY, POSSIBLE OVERWRITING PROBLEM ***");
- return new Number.integer (0);
- }
-
- /* PROPAGATE CARRIES AT END AND EVERY EIGHTH TIME,
- * FASTER THAN DOING IT EVERY TIME.
- */
- for (var j = T + 3; j >= 0; j--)
- {
- int ri = r.re_fraction[j] + c;
- if (ri < 0)
- {
- mperr ("*** INTEGER OVERFLOW IN MULTIPLY, B TOO LARGE ***");
- return new Number.integer (0);
- }
- c = ri / BASE;
- r.re_fraction[j] = ri - BASE * c;
- }
- if (c != 0)
- {
- mperr ("*** ILLEGAL BASE B DIGIT IN CALL TO MULTIPLY, POSSIBLE OVERWRITING PROBLEM ***");
- return new Number.integer (0);
- }
- c = 8;
- }
-
- if (c != 8)
- {
- c = 0;
- for (var i = T + 3; i >= 0; i--)
- {
- int ri = r.re_fraction[i] + c;
- if (ri < 0)
- {
- mperr ("*** INTEGER OVERFLOW IN MULTIPLY, B TOO LARGE ***");
- return new Number.integer (0);
- }
- c = ri / BASE;
- r.re_fraction[i] = ri - BASE * c;
- }
-
- if (c != 0)
- {
- mperr ("*** ILLEGAL BASE B DIGIT IN CALL TO MULTIPLY, POSSIBLE OVERWRITING PROBLEM ***");
- return new Number.integer (0);
- }
- }
-
- /* Clear complex part */
- z.im_sign = 0;
- z.im_exponent = 0;
- for (var i = 0; i < z.im_fraction.length; i++)
- z.im_fraction[i] = 0;
-
- /* NORMALIZE AND ROUND RESULT */
- // FIXME: Use stack variable because of mp_normalize brokeness
- for (var i = 0; i < SIZE; i++)
- z.re_fraction[i] = r.re_fraction[i];
- mp_normalize (ref z);
-
+ var tmp = z.re_num;
+ tmp.root (re_num, (ulong) n, Round.NEAREST);
+ z.re_num = tmp;
return z;
}
- private Number multiply_integer_real (int64 y)
+ private Number ln_real ()
{
- /* x*0 = 0*y = 0 */
- if (is_zero () || y == 0)
- return new Number.integer (0);
-
- /* x*1 = x, x*-1 = -x */
- // FIXME: Why is this not working? mp_ext is using this function to do a normalization
- /*if (y == 1 || y == -1)
- {
- if (y < 0)
- z = invert_sign ();
- else
- z = this;
- return z;
- }*/
-
- /* Copy x as z may also refer to x */
- var z = new Number.integer (0);
-
- if (y < 0)
- {
- y = -y;
- z.re_sign = -re_sign;
- }
- else
- z.re_sign = re_sign;
- z.re_exponent = re_exponent + 4;
-
- /* FORM PRODUCT IN ACCUMULATOR */
- int64 c = 0;
-
- /* IF y*B NOT REPRESENTABLE AS AN INTEGER WE HAVE TO SIMULATE
- * DOUBLE-PRECISION MULTIPLICATION.
- */
-
- /* Computing MAX */
- if (y >= int.max (BASE << 3, 32767 / BASE))
- {
- /* HERE J IS TOO LARGE FOR SINGLE-PRECISION MULTIPLICATION */
- var j1 = y / BASE;
- var j2 = y - j1 * BASE;
-
- /* FORM PRODUCT */
- for (var i = T + 3; i >= 0; i--)
- {
- var c1 = c / BASE;
- var c2 = c - BASE * c1;
- var ix = 0;
- if (i > 3)
- ix = re_fraction[i - 4];
-
- var t = j2 * ix + c2;
- var is = t / BASE;
- c = j1 * ix + c1 + is;
- z.re_fraction[i] = (int) (t - BASE * is);
- }
- }
- else
- {
- int64 ri = 0;
- for (var i = T + 3; i >= 4; i--)
- {
- ri = y * re_fraction[i - 4] + c;
- c = ri / BASE;
- z.re_fraction[i] = (int) (ri - BASE * c);
- }
-
- /* CHECK FOR INTEGER OVERFLOW */
- if (ri < 0)
- {
- mperr ("*** INTEGER OVERFLOW IN multiply_integer, B TOO LARGE ***");
- return new Number.integer (0);
- }
-
- /* HAVE TO TREAT FIRST FOUR WORDS OF R SEPARATELY */
- for (var i = 3; i >= 0; i--)
- {
- var t = c;
- c = t / BASE;
- z.re_fraction[i] = (int) (t - BASE * c);
- }
- }
-
- /* HAVE TO SHIFT RIGHT HERE AS CARRY OFF END */
- while (c != 0)
- {
- for (var i = T + 3; i >= 1; i--)
- z.re_fraction[i] = z.re_fraction[i - 1];
- var t = c;
- c = t / BASE;
- z.re_fraction[0] = (int) (t - BASE * c);
- z.re_exponent++;
- }
-
- if (c < 0)
- {
- mperr ("*** INTEGER OVERFLOW IN multiply_integer, B TOO LARGE ***");
- return new Number.integer (0);
- }
-
- z.im_sign = 0;
- z.im_exponent = 0;
- for (var i = 0; i < z.im_fraction.length; i++)
- z.im_fraction[i] = 0;
- mp_normalize (ref z);
-
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.log (re_num, Round.NEAREST);
+ var z = new Number.mpfloat (tmp);
return z;
}
@@ -2586,215 +1293,19 @@ public class Number : Object
/* 1/0 invalid */
if (is_zero ())
{
- mperr (_("Reciprocal of zero is undefined"));
+ error = _("Reciprocal of zero is undefined");
return new Number.integer (0);
}
- /* Start by approximating value using floating point */
- var t1 = copy ();
- t1.re_exponent = 0;
- t1 = new Number.double (1.0 / t1.to_double ());
- t1.re_exponent -= re_exponent;
-
- var t = 3;
- var it0 = t;
- Number t2;
- while (true)
- {
- /* t1 = t1 - (t1 * ((x * t1) - 1)) (2*t1 - t1^2*x) */
- t2 = multiply (t1);
- t2 = t2.add (new Number.integer (-1));
- t2 = t1.multiply (t2);
- t1 = t1.subtract (t2);
- if (t >= T)
- break;
-
- /* FOLLOWING LOOP ALMOST DOUBLES T (POSSIBLE
- * BECAUSE NEWTONS METHOD HAS 2ND ORDER CONVERGENCE).
- */
- var ts3 = t;
- var ts2 = 0;
- t = T;
- do
- {
- ts2 = t;
- t = (t + it0) / 2;
- } while (t > ts3);
- t = int.min (ts2, T);
- }
-
- /* RETURN IF NEWTON ITERATION WAS CONVERGING */
- if (t2.re_sign != 0 && (t1.re_exponent - t2.re_exponent) << 1 < T - it0)
- {
- /* THE FOLLOWING MESSAGE MAY INDICATE THAT B**(T-1) IS TOO SMALL,
- * OR THAT THE STARTING APPROXIMATION IS NOT ACCURATE ENOUGH.
- */
- mperr ("*** ERROR OCCURRED IN RECIPROCAL, NEWTON ITERATION NOT CONVERGING PROPERLY ***");
- }
-
- return t1;
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.set_unsigned_integer (1, Round.NEAREST);
+ tmp.divide (tmp, re_num, Round.NEAREST);
+ var z = copy ();
+ z.re_num.clear ();
+ z.re_num = tmp;
+ return z;
}
- private Number divide_integer_real (int64 y)
- {
- /* x/0 */
- if (y == 0)
- {
- /* Translators: Error displayed attempted to divide by zero */
- mperr (_("Division by zero is undefined"));
- return new Number.integer (0);
- }
-
- /* 0/y = 0 */
- if (is_zero ())
- return new Number.integer (0);
-
- /* Division by -1 or 1 just changes re_sign */
- if (y == 1 || y == -1)
- {
- if (y < 0)
- return invert_sign ();
- else
- return this;
- }
-
- var z = new Number.integer (0);
- if (y < 0)
- {
- y = -y;
- z.re_sign = -re_sign;
- }
- else
- z.re_sign = re_sign;
- z.re_exponent = re_exponent;
-
- int64 c = 0;
- int64 i = 0;
-
- /* IF y*B NOT REPRESENTABLE AS AN INTEGER HAVE TO SIMULATE
- * LONG DIVISION. ASSUME AT LEAST 16-BIT WORD.
- */
-
- /* Computing MAX */
- var b2 = int.max (BASE << 3, 32767 / BASE);
- if (y < b2)
- {
- /* LOOK FOR FIRST NONZERO DIGIT IN QUOTIENT */
- int64 r1 = 0;
- do
- {
- c = BASE * c;
- if (i < T)
- c += re_fraction[i];
- i++;
- r1 = c / y;
- if (r1 < 0)
- {
- mperr ("*** INTEGER OVERFLOW IN DIVIDE_INTEGER, B TOO LARGE ***");
- return new Number.integer (0);
- }
- } while (r1 == 0);
-
- /* ADJUST re_exponent AND GET T+4 DIGITS IN QUOTIENT */
- z.re_exponent += (int) (1 - i);
- z.re_fraction[0] = (int) r1;
- c = BASE * (c - y * r1);
- int64 kh = 1;
- if (i < T)
- {
- kh = T + 1 - i;
- for (var k = 1; k < kh; k++)
- {
- c += re_fraction[i];
- z.re_fraction[k] = (int) (c / y);
- c = BASE * (c - y * z.re_fraction[k]);
- i++;
- }
- if (c < 0)
- {
- mperr ("*** INTEGER OVERFLOW IN DIVIDE_INTEGER, B TOO LARGE ***");
- return new Number.integer (0);
- }
- }
-
- for (var k = kh; k < T + 4; k++)
- {
- z.re_fraction[k] = (int) (c / y);
- c = BASE * (c - y * z.re_fraction[k]);
- }
- if (c < 0)
- {
- mperr ("*** INTEGER OVERFLOW IN DIVIDE_INTEGER, B TOO LARGE ***");
- return new Number.integer (0);
- }
-
- mp_normalize (ref z);
- return z;
- }
-
- /* HERE NEED SIMULATED DOUBLE-PRECISION DIVISION */
- var j1 = y / BASE;
- var j2 = y - j1 * BASE;
-
- /* LOOK FOR FIRST NONZERO DIGIT */
- var c2 = 0;
- do
- {
- c = BASE * c + c2;
- c2 = i < T ? re_fraction[i] : 0;
- i++;
- } while (c < j1 || (c == j1 && c2 < j2));
-
- /* COMPUTE T+4 QUOTIENT DIGITS */
- z.re_exponent += (int) (1 - i);
- i--;
-
- /* MAIN LOOP FOR LARGE ABS (y) CASE */
- for (var k = 1; k <= T + 4; k++)
- {
- /* GET APPROXIMATE QUOTIENT FIRST */
- var ir = c / (j1 + 1);
-
- /* NOW REDUCE SO OVERFLOW DOES NOT OCCUR */
- var iq = c - ir * j1;
- if (iq >= b2)
- {
- /* HERE IQ*B WOULD POSSIBLY OVERFLOW SO INCREASE IR */
- ir++;
- iq -= j1;
- }
-
- iq = iq * BASE - ir * j2;
- if (iq < 0)
- {
- /* HERE IQ NEGATIVE SO IR WAS TOO LARGE */
- ir--;
- iq += y;
- }
-
- if (i < T)
- iq += re_fraction[i];
- i++;
- var iqj = iq / y;
-
- /* r (K) = QUOTIENT, C = REMAINDER */
- z.re_fraction[k - 1] = (int) (iqj + ir);
- c = iq - y * iqj;
-
- if (c < 0)
- {
- /* CARRY NEGATIVE SO OVERFLOW MUST HAVE OCCURRED */
- mperr ("*** INTEGER OVERFLOW IN DIVIDE_INTEGER, B TOO LARGE ***");
- return new Number.integer (0);
- }
- }
-
- mp_normalize (ref z);
-
- /* CARRY NEGATIVE SO OVERFLOW MUST HAVE OCCURRED */
- mperr ("*** INTEGER OVERFLOW IN DIVIDE_INTEGER, B TOO LARGE ***");
- return new Number.integer (0);
- }
private Number from_radians (AngleUnit unit)
{
@@ -2829,145 +1340,23 @@ public class Number : Object
}
}
- /* z = sin (x) -1 >= x >= 1, do_sin = 1
- * z = cos (x) -1 >= x >= 1, do_sin = 0
- */
- private Number sin1 (bool do_sin)
- {
- /* sin (0) = 0, cos (0) = 1 */
- if (is_zero ())
- {
- if (do_sin)
- return new Number.integer (0);
- else
- return new Number.integer (1);
- }
-
- var t2 = multiply (this);
- if (t2.compare (new Number.integer (1)) > 0)
- mperr ("*** ABS (X) > 1 IN CALL TO SIN1 ***");
-
- Number t1;
- int i;
- Number z;
- if (do_sin)
- {
- t1 = this;
- z = t1;
- i = 2;
- }
- else
- {
- t1 = new Number.integer (1);
- z = new Number.integer (0);
- i = 1;
- }
-
- /* Taylor series */
- /* POWER SERIES LOOP. REDUCE T IF POSSIBLE */
- var b2 = 2 * int.max (BASE, 64);
- do
- {
- if (T + t1.re_exponent <= 0)
- break;
-
- /* IF I*(I+1) IS NOT REPRESENTABLE AS AN INTEGER, THE FOLLOWING
- * DIVISION BY I*(I+1) HAS TO BE SPLIT UP.
- */
- t1 = t2.multiply (t1);
- if (i > b2)
- {
- t1 = t1.divide_integer (-i);
- t1 = t1.divide_integer (i + 1);
- }
- else
- t1 = t1.divide_integer (-i * (i + 1));
- z = t1.add (z);
-
- i += 2;
- } while (t1.re_sign != 0);
-
- if (!do_sin)
- z = z.add (new Number.integer (1));
-
- return z;
- }
-
private Number sin_real (AngleUnit unit)
{
- /* sin (0) = 0 */
- if (is_zero ())
- return new Number.integer (0);
-
var x_radians = to_radians (unit);
-
- var xs = x_radians.re_sign;
- x_radians = x_radians.abs ();
-
- /* USE SIN1 IF ABS (X) <= 1 */
- Number z;
- if (x_radians.compare (new Number.integer (1)) <= 0)
- z = x_radians.sin1 (true);
- /* FIND ABS (X) MODULO 2PI */
- else
- {
- z = new Number.pi ().divide_integer (4);
- x_radians = x_radians.divide (z);
- x_radians = x_radians.divide_integer (8);
- x_radians = x_radians.fractional_component ();
-
- /* SUBTRACT 1/2, SAVE re_sign AND TAKE ABS */
- x_radians = x_radians.add (new Number.fraction (-1, 2));
- xs = -xs * x_radians.re_sign;
- if (xs == 0)
- return new Number.integer (0);
-
- x_radians.re_sign = 1;
- x_radians = x_radians.multiply_integer (4);
-
- /* IF NOT LESS THAN 1, SUBTRACT FROM 2 */
- if (x_radians.re_exponent > 0)
- x_radians = x_radians.add (new Number.integer (-2));
-
- if (x_radians.is_zero ())
- return new Number.integer (0);
-
- x_radians.re_sign = 1;
- x_radians = x_radians.multiply_integer (2);
-
- /* NOW REDUCED TO FIRST QUADRANT, IF LESS THAN PI/4 USE
- * POWER SERIES, ELSE COMPUTE COS OF COMPLEMENT
- */
- if (x_radians.re_exponent > 0)
- {
- x_radians = x_radians.add (new Number.integer (-2));
- x_radians = x_radians.multiply (z);
- z = x_radians.sin1 (false);
- }
- else
- {
- x_radians = x_radians.multiply (z);
- z = x_radians.sin1 (true);
- }
- }
-
- z.re_sign = xs;
+ var z = new Number.integer (0);
+ var tmp = z.re_num;
+ tmp.sin (x_radians.re_num, Round.NEAREST);
+ z.re_num = tmp;
return z;
}
private Number cos_real (AngleUnit unit)
{
- /* cos (0) = 1 */
- if (is_zero ())
- return new Number.integer (1);
-
- /* Use power series if |x| <= 1 */
- var z = to_radians (unit).abs ();
- if (z.compare (new Number.integer (1)) <= 0)
- return z.sin1 (false);
- else
- /* cos (x) = sin (π/2 - |x|) */
- return new Number.pi ().divide_integer (2).subtract (z).sin (AngleUnit.RADIANS);
+ var x_radians = to_radians (unit);
+ var tmp = MPFloat.init2 ((Precision) precision);
+ tmp.cos (x_radians.re_num, Round.NEAREST);
+ var z = new Number.mpfloat (tmp);
+ return z;
}
private Number bitwise (Number y, BitwiseFunc bitwise_operator, int wordlen)
@@ -2981,7 +1370,7 @@ public class Number : Object
offset_out = offset1 > offset2 ? offset1 : offset2;
if (offset_out > 0 && (offset_out < offset1 || offset_out < offset2))
{
- mperr ("Overflow. Try a bigger word size");
+ error = ("Overflow. Try a bigger word size");
return new Number.integer (0);
}
@@ -3031,29 +1420,6 @@ public class Number : Object
// FIXME: Re-add overflow and underflow detection
-static string? mp_error = null;
-
-/* THIS ROUTINE IS CALLED WHEN AN ERROR CONDITION IS ENCOUNTERED, AND
- * AFTER A MESSAGE HAS BEEN WRITTEN TO STDERR.
- */
-public void mperr (string text)
-{
- mp_error = text;
-}
-
-/* Returns error string or null if no error */
-// FIXME: Global variable
-public string mp_get_error ()
-{
- return mp_error;
-}
-
-/* Clear any current error */
-public void mp_clear_error ()
-{
- mp_error = null;
-}
-
/* Sets z from a string representation in 'text'. */
public Number? mp_set_from_string (string str, int default_base = 10)
{
@@ -3102,6 +1468,7 @@ public Number? mp_set_from_string (string str, int default_base = 10)
/* 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);
@@ -3233,73 +1600,6 @@ private Number? set_from_sexagesimal (string str)
return null;
}
-/* RETURNS K = K/GCD AND L = L/GCD, WHERE GCD IS THE
- * GREATEST COMMON DIVISOR OF K AND L.
- * SAVE INPUT PARAMETERS IN LOCAL VARIABLES
- */
-public void mp_gcd (ref int64 k, ref int64 l)
-{
- var i = k.abs ();
- var j = l.abs ();
- if (j == 0)
- {
- /* IF J = 0 RETURN (1, 0) UNLESS I = 0, THEN (0, 0) */
- k = 1;
- l = 0;
- if (i == 0)
- k = 0;
- return;
- }
-
- /* EUCLIDEAN ALGORITHM LOOP */
- do
- {
- i %= j;
- if (i == 0)
- {
- k = k / j;
- l = l / j;
- return;
- }
- j %= i;
- } while (j != 0);
-
- /* HERE J IS THE GCD OF K AND L */
- k = k / i;
- l = l / i;
-}
-
-// FIXME: Is r.re_fraction large enough? It seems to be in practise but it may be T+4 instead of T
-// FIXME: There is some sort of stack corruption/use of unitialised variables here. Some functions are
-// using stack variables as x otherwise there are corruption errors. e.g. "Cos (45) - 1/Sqrt (2) = -0"
-// (try in scientific mode)
-public void mp_normalize (ref Number x)
-{
- int start_index;
-
- /* Find first non-zero digit */
- for (start_index = 0; start_index < SIZE && x.re_fraction[start_index] == 0; start_index++);
-
- /* Mark as zero */
- if (start_index >= SIZE)
- {
- x.re_sign = 0;
- x.re_exponent = 0;
- return;
- }
-
- /* Shift left so first digit is non-zero */
- if (start_index > 0)
- {
- x.re_exponent -= start_index;
- var i = 0;
- for (; (i + start_index) < SIZE; i++)
- x.re_fraction[i] = x.re_fraction[i + start_index];
- for (; i < SIZE; i++)
- x.re_fraction[i] = 0;
- }
-}
-
/* Returns true if x is cannot be represented in a binary word of length 'wordlen' */
public bool mp_is_overflow (Number x, int wordlen)
{
diff --git a/src/serializer.vala b/src/serializer.vala
index 3568b33..7cb78f2 100644
--- a/src/serializer.vala
+++ b/src/serializer.vala
@@ -32,6 +32,9 @@ public class Serializer : Object
private unichar tsep; /* Locale specific thousands separator. */
private int tsep_count; /* Number of digits between separator. */
+ /* is set when an error (for example precision error while converting) occurs */
+ public string? error { get; set; default = null; }
+
public Serializer (DisplayFormat format, int number_base, int trailing_digits)
{
var radix_string = Posix.nl_langinfo (Posix.NLItem.RADIXCHAR);
@@ -318,7 +321,18 @@ public class Serializer : Object
var t3 = temp.subtract (t2);
var d = t3.to_integer ();
- string.prepend_c (d < 16 ? digits[d] : '?');
+
+ if (d < 16 && d >= 0)
+ {
+ string.prepend_c (digits[d]);
+ }
+ else
+ {
+ string.prepend_c ('?');
+ error = _("Precision error");
+ string.assign ("0");
+ break;
+ }
n_digits++;
temp = t;
diff --git a/src/test-equation.vala b/src/test-equation.vala
index 48044ca..423d309 100644
--- a/src/test-equation.vala
+++ b/src/test-equation.vala
@@ -1,13 +1,13 @@
/*
* Copyright (C) 2008-2012 Robert Ancell.
- *
+ *
* 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 2 of the License, or (at your option) any later
* version. See http://www.gnu.org/copyleft/gpl.html the full text of the
* license.
*/
-
+
private int number_base = 10;
private int wordlen = 32;
private AngleUnit angle_units = AngleUnit.DEGREES;
@@ -20,7 +20,7 @@ private int pass_count = 0;
private string error_code_to_string (ErrorCode error)
{
if (error == ErrorCode.MP)
- return "ErrorCode.MP(\"%s\")".printf (mp_get_error ());
+ return "ErrorCode.MP(\"%s\")".printf (Number.error);
return mp_error_code_to_string (error);
}
@@ -115,7 +115,7 @@ private class TestEquation : Equation
{
if (!enable_conversions)
return null;
-
+
return UnitManager.get_default ().convert_by_symbol (x, x_units, z_units);
}
}
@@ -133,19 +133,19 @@ private void test_conversions ()
test ("100 gradians in degrees", "90", 0);
/* Length */
- test ("1 meter in mm", "1000", 0);
+ test ("1 meter in mm", "1000", 0);
test ("1m in mm", "1000", 0);
test ("1 inch in cm", "2.54", 0);
/* Area */
test ("1m² in mm²", "1000000", 0);
-
+
/* Volume */
- test ("1m³ in mm³", "1000000000", 0);
+ test ("1m³ in mm³", "1000000000", 0);
/* Weight */
test ("1 kg in pounds", "2.204622622", 0);
-
+
/* Duration */
test ("1 minute in seconds", "60", 0);
test ("1s in ms", "1000", 0);
@@ -223,7 +223,7 @@ private void test_equations ()
test ("١٢٣٤٥٦٧٨٩٠", "1234567890", 0);
test ("۱۲۳۴۵۶۷۸۹۰", "1234567890", 0);
-/*
+/*
//test ("2A", "2000000000000000", 0);
test ("2T", "2000000000000", 0);
test ("2G", "2000000000", 0);
@@ -263,7 +263,7 @@ private void test_equations ()
test ("2y", "6", 0);
test ("y2", "", ErrorCode.INVALID);
test ("y 2", "", ErrorCode.INVALID);
- test ("2z", "", ErrorCode.UNKNOWN_VARIABLE);
+ test ("2z", "", ErrorCode.UNKNOWN_VARIABLE);
test ("z2", "", ErrorCode.UNKNOWN_VARIABLE);
test ("z 2", "", ErrorCode.UNKNOWN_VARIABLE);
test ("z(2)", "", ErrorCode.UNKNOWN_FUNCTION);
@@ -414,7 +414,7 @@ private void test_equations ()
test ("-21 mod 9", "6", 0);
test ("-21 mod -9", "−3", 0);
- test ("sgn 0", "0", 0);
+ test ("sgn 0", "0", 0);
test ("sgn 3", "1", 0);
test ("sgn −3", "−1", 0);
test ("⌊3⌋", "3", 0);
@@ -530,16 +530,16 @@ private void test_equations ()
test ("i", "i", 0);
test ("−i", "−i", 0);
test ("2i", "2i", 0);
- test ("1+i", "1+i", 0);
+ test ("1+i", "1+i", 0);
test ("i+1", "1+i", 0);
- test ("1−i", "1−i", 0);
+ test ("1−i", "1−i", 0);
test ("i−1", "−1+i", 0);
test ("i×i", "−1", 0);
test ("i÷i", "1", 0);
test ("1÷i", "−i", 0);
test ("|i|", "1", 0);
test ("|3+4i|", "5", 0);
- test ("arg 0", "", ErrorCode.MP);
+ test ("arg 0", "", ErrorCode.MP);
test ("arg 1", "0", 0);
test ("arg (1+i)", "45", 0);
test ("arg i", "90", 0);
@@ -565,9 +565,9 @@ private void test_equations ()
test ("1 and 1", "1", 0);
test ("3 and 5", "1", 0);
- test ("0 or 0", "0", 0);
+ test ("0 or 0", "0", 0);
test ("1 or 0", "1", 0);
- test ("0 or 1", "1", 0);
+ test ("0 or 1", "1", 0);
test ("1 or 1", "1", 0);
test ("3 or 5", "7", 0);
diff --git a/src/test-number.vala b/src/test-number.vala
index b94535b..cb346a4 100644
--- a/src/test-number.vala
+++ b/src/test-number.vala
@@ -72,21 +72,6 @@ private void test_fraction ()
pass ();
}
-private void test_float ()
-{
- for (var a = -10.0f; a <= 10.0f; a += 0.5f)
- {
- var z = new Number.float (a);
- if (z.to_float () != a)
- {
- fail ("Number.float (%f).to_float () -> %f, expected %f".printf (a, z.to_float (), a));
- return;
- }
- }
-
- pass ();
-}
-
private void test_double ()
{
for (var a = -10.0; a <= 10.0; a += 0.5)
@@ -1089,7 +1074,6 @@ static int main (string[] args)
test_integer ();
test_unsigned_integer ();
test_fraction ();
- test_float ();
test_double ();
test_complex ();
test_polar ();
diff --git a/src/unit.vala b/src/unit.vala
index c6eb866..a051588 100644
--- a/src/unit.vala
+++ b/src/unit.vala
@@ -13,7 +13,7 @@ private UnitManager? default_unit_manager = null;
public class UnitManager : Object
{
private List<UnitCategory> categories;
-
+
public UnitManager ()
{
categories = new List<UnitCategory> ();
@@ -313,7 +313,7 @@ private class UnitSolveEquation : Equation
base (function);
this.x = x;
}
-
+
public override bool variable_is_defined (string name)
{
return true;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]