Split Num into its own file

This commit is contained in:
Tiffany Bennett 2016-10-08 18:57:20 -04:00
parent c31d862059
commit f5623c2f8e
13 changed files with 209 additions and 194 deletions

View file

@ -4,7 +4,7 @@
use std::rc::Rc;
use std::fmt;
use number::Num;
use num::Num;
#[derive(Debug, Clone)]
pub enum SuffixOp {

View file

@ -3,7 +3,8 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use std::collections::{BTreeMap, BTreeSet};
use number::{Dim, Number, Unit, Num};
use number::{Dim, Number, Unit};
use num::Num;
use ast::{Expr, DatePattern};
use search;
use substance::Substance;

View file

@ -8,7 +8,7 @@ use xml::EventReader;
use xml::reader::XmlEvent;
use ast::{Defs, Def, Expr};
use std::rc::Rc;
use number::Num;
use num::Num;
static URL: &'static str = "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml";

View file

@ -6,7 +6,8 @@ use ast::{DatePattern, DateToken, show_datepattern};
use chrono::format::Parsed;
use chrono::{Weekday, DateTime, UTC, FixedOffset, Duration, Date};
use context::Context;
use number::{Number, Num, Dim};
use number::{Number, Dim};
use num::Num;
use std::iter::Peekable;
pub fn parse_date<I>(

View file

@ -3,7 +3,8 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use std::collections::BTreeMap;
use number::{Number, Num, Int, Dim, NumberParts, pow};
use number::{Number, Dim, NumberParts, pow};
use num::{Num, Int};
use date;
use ast::{Expr, SuffixOp, Query, Conversion};
use std::rc::Rc;

View file

@ -4,7 +4,8 @@
use std::collections::{BTreeMap, BinaryHeap};
use std::rc::Rc;
use number::{Number, Num, Unit, Dim};
use number::{Number, Unit, Dim};
use num::Num;
use std::cmp;
#[derive(PartialEq, Eq, Debug)]

View file

@ -6,7 +6,7 @@ use std::str::Chars;
use std::iter::Peekable;
use std::rc::Rc;
use ast::*;
use number::Num;
use num::Num;
#[derive(Debug, Clone)]
pub enum Token {

View file

@ -56,6 +56,7 @@ extern crate serde_derive;
pub mod text_query;
pub mod context;
pub mod eval;
pub mod num;
pub mod number;
pub mod date;
pub mod factorize;

View file

@ -3,7 +3,8 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use std::collections::{BTreeMap, BTreeSet};
use number::{Number, Dim, Num};
use number::{Number, Dim};
use num::Num;
use ast::{Expr, Def, Defs};
use substance::{Substance, Property, Properties};
use std::rc::Rc;

191
src/num.rs Normal file
View file

@ -0,0 +1,191 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use gmp::mpq::Mpq;
use gmp::mpz::Mpz;
use std::ops::{Add, Div, Mul, Neg, Sub};
use std::cmp::Ordering;
pub type Int = Mpz;
/// Number type.
#[derive(Clone, PartialEq, Debug)]
pub enum Num {
/// Arbitrary-precision rational fraction.
Mpq(Mpq),
/// Machine floats.
Float(f64),
// /// Machine ints.
// Int(i64),
}
enum NumParity {
Mpq(Mpq, Mpq),
Float(f64, f64)
}
impl Num {
pub fn one() -> Num {
Num::Mpq(Mpq::one())
//Num::Int(1)
}
pub fn zero() -> Num {
Num::Mpq(Mpq::zero())
//Num::Int(0)
}
pub fn abs(&self) -> Num {
match *self {
Num::Mpq(ref mpq) => Num::Mpq(mpq.abs()),
Num::Float(f) => Num::Float(f.abs()),
}
}
fn parity(&self, other: &Num) -> NumParity {
match (self, other) {
(&Num::Float(left), right) =>
NumParity::Float(left, right.into()),
(left, &Num::Float(right)) =>
NumParity::Float(left.into(), right),
(&Num::Mpq(ref left), &Num::Mpq(ref right)) =>
NumParity::Mpq(left.clone(), right.clone()),
}
}
pub fn div_rem(&self, other: &Num) -> (Num, Num) {
match self.parity(other) {
NumParity::Mpq(left, right) => {
let div = &left / &right;
let floor = &div.get_num() / div.get_den();
let rem = &left - &(&right * &Mpq::ratio(&floor, &Mpz::one()));
(Num::Mpq(Mpq::ratio(&floor, &Mpz::one())), Num::Mpq(rem))
},
NumParity::Float(left, right) => {
(Num::Float(left / right), Num::Float(left % right))
},
}
}
pub fn to_rational(&self) -> (Int, Int) {
match *self {
Num::Mpq(ref mpq) => (mpq.get_num(), mpq.get_den()),
Num::Float(mut x) => {
let mut m = [
[1, 0],
[0, 1]
];
let maxden = 1_000_000;
// loop finding terms until denom gets too big
loop {
let ai = x as i64;
if m[1][0] * ai + m[1][1] > maxden {
break;
}
let mut t;
t = m[0][0] * ai + m[0][1];
m[0][1] = m[0][0];
m[0][0] = t;
t = m[1][0] * ai + m[1][1];
m[1][1] = m[1][0];
m[1][0] = t;
if x == ai as f64 {
break; // division by zero
}
x = 1.0/(x - ai as f64);
if x as i64 > i64::max_value() / 2 {
break; // representation failure
}
}
(Int::from(m[0][0]), Int::from(m[1][0]))
},
}
}
pub fn to_int(&self) -> Option<i64> {
match *self {
Num::Mpq(ref mpq) => (&(mpq.get_num() / mpq.get_den())).into(),
Num::Float(f) => if f.abs() < i64::max_value() as f64 {
Some(f as i64)
} else {
None
},
}
}
pub fn to_f64(&self) -> f64 {
self.into()
}
}
impl From<Mpq> for Num {
fn from(mpq: Mpq) -> Num {
Num::Mpq(mpq)
}
}
impl From<Mpz> for Num {
fn from(mpz: Mpz) -> Num {
Num::Mpq(Mpq::ratio(&mpz, &Mpz::one()))
}
}
impl From<i64> for Num {
fn from(i: i64) -> Num {
Num::from(Mpz::from(i))
}
}
impl<'a> Into<f64> for &'a Num {
fn into(self) -> f64 {
match *self {
Num::Mpq(ref mpq) => mpq.clone().into(),
Num::Float(f) => f,
}
}
}
impl PartialOrd for Num {
fn partial_cmp(&self, other: &Num) -> Option<Ordering> {
match self.parity(other) {
NumParity::Mpq(left, right) => left.partial_cmp(&right),
NumParity::Float(left, right) => left.partial_cmp(&right),
}
}
}
macro_rules! num_binop {
($what:ident, $func:ident) => {
impl<'a, 'b> $what<&'b Num> for &'a Num {
type Output = Num;
fn $func(self, other: &'b Num) -> Num {
match self.parity(other) {
NumParity::Mpq(left, right) =>
Num::Mpq(left.$func(&right)),
NumParity::Float(left, right) =>
Num::Float(left.$func(&right)),
}
}
}
}
}
num_binop!(Add, add);
num_binop!(Sub, sub);
num_binop!(Mul, mul);
num_binop!(Div, div);
impl<'a> Neg for &'a Num {
type Output = Num;
fn neg(self) -> Num {
match *self {
Num::Mpq(ref mpq) => Num::Mpq(-mpq),
Num::Float(f) => Num::Float(-f),
}
}
}

View file

@ -11,190 +11,7 @@ use std::rc::Rc;
use std::fmt;
use std::borrow::Borrow;
use context::Context;
use std::cmp::Ordering;
pub type Int = Mpz;
/// Number type.
#[derive(Clone, PartialEq, Debug)]
pub enum Num {
/// Arbitrary-precision rational fraction.
Mpq(Mpq),
/// Machine floats.
Float(f64),
// /// Machine ints.
// Int(i64),
}
enum NumParity {
Mpq(Mpq, Mpq),
Float(f64, f64)
}
impl Num {
pub fn one() -> Num {
Num::Mpq(Mpq::one())
//Num::Int(1)
}
pub fn zero() -> Num {
Num::Mpq(Mpq::zero())
//Num::Int(0)
}
pub fn abs(&self) -> Num {
match *self {
Num::Mpq(ref mpq) => Num::Mpq(mpq.abs()),
Num::Float(f) => Num::Float(f.abs()),
}
}
fn parity(&self, other: &Num) -> NumParity {
match (self, other) {
(&Num::Float(left), right) =>
NumParity::Float(left, right.into()),
(left, &Num::Float(right)) =>
NumParity::Float(left.into(), right),
(&Num::Mpq(ref left), &Num::Mpq(ref right)) =>
NumParity::Mpq(left.clone(), right.clone()),
}
}
pub fn div_rem(&self, other: &Num) -> (Num, Num) {
match self.parity(other) {
NumParity::Mpq(left, right) => {
let div = &left / &right;
let floor = &div.get_num() / div.get_den();
let rem = &left - &(&right * &Mpq::ratio(&floor, &Mpz::one()));
(Num::Mpq(Mpq::ratio(&floor, &Mpz::one())), Num::Mpq(rem))
},
NumParity::Float(left, right) => {
(Num::Float(left / right), Num::Float(left % right))
},
}
}
pub fn to_rational(&self) -> (Int, Int) {
match *self {
Num::Mpq(ref mpq) => (mpq.get_num(), mpq.get_den()),
Num::Float(mut x) => {
let mut m = [
[1, 0],
[0, 1]
];
let maxden = 1_000_000;
// loop finding terms until denom gets too big
loop {
let ai = x as i64;
if m[1][0] * ai + m[1][1] > maxden {
break;
}
let mut t;
t = m[0][0] * ai + m[0][1];
m[0][1] = m[0][0];
m[0][0] = t;
t = m[1][0] * ai + m[1][1];
m[1][1] = m[1][0];
m[1][0] = t;
if x == ai as f64 {
break; // division by zero
}
x = 1.0/(x - ai as f64);
if x as i64 > i64::max_value() / 2 {
break; // representation failure
}
}
(Int::from(m[0][0]), Int::from(m[1][0]))
},
}
}
pub fn to_int(&self) -> Option<i64> {
match *self {
Num::Mpq(ref mpq) => (&(mpq.get_num() / mpq.get_den())).into(),
Num::Float(f) => if f.abs() < i64::max_value() as f64 {
Some(f as i64)
} else {
None
},
}
}
pub fn to_f64(&self) -> f64 {
self.into()
}
}
impl From<Mpq> for Num {
fn from(mpq: Mpq) -> Num {
Num::Mpq(mpq)
}
}
impl From<Mpz> for Num {
fn from(mpz: Mpz) -> Num {
Num::Mpq(Mpq::ratio(&mpz, &Mpz::one()))
}
}
impl From<i64> for Num {
fn from(i: i64) -> Num {
Num::from(Mpz::from(i))
}
}
impl<'a> Into<f64> for &'a Num {
fn into(self) -> f64 {
match *self {
Num::Mpq(ref mpq) => mpq.clone().into(),
Num::Float(f) => f,
}
}
}
impl PartialOrd for Num {
fn partial_cmp(&self, other: &Num) -> Option<Ordering> {
match self.parity(other) {
NumParity::Mpq(left, right) => left.partial_cmp(&right),
NumParity::Float(left, right) => left.partial_cmp(&right),
}
}
}
macro_rules! num_binop {
($what:ident, $func:ident) => {
impl<'a, 'b> $what<&'b Num> for &'a Num {
type Output = Num;
fn $func(self, other: &'b Num) -> Num {
match self.parity(other) {
NumParity::Mpq(left, right) =>
Num::Mpq(left.$func(&right)),
NumParity::Float(left, right) =>
Num::Float(left.$func(&right)),
}
}
}
}
}
num_binop!(Add, add);
num_binop!(Sub, sub);
num_binop!(Mul, mul);
num_binop!(Div, div);
impl<'a> Neg for &'a Num {
type Output = Num;
fn neg(self) -> Num {
match *self {
Num::Mpq(ref mpq) => Num::Mpq(-mpq),
Num::Float(f) => Num::Float(-f),
}
}
}
use num::*;
/// Alias for the primary representation of dimensionality.
pub type Unit = BTreeMap<Dim, i64>;

View file

@ -3,7 +3,8 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use context::Context;
use number::{Number, Num, Dim};
use number::{Number, Dim};
use num::Num;
use value::Show;
use std::collections::BTreeMap;
use reply::{PropertyReply, SubstanceReply};

View file

@ -7,7 +7,7 @@ use std::iter::Peekable;
use ast::*;
use gmp::mpz::Mpz;
use gmp::mpq::Mpq;
use number::Num;
use num::Num;
#[derive(Debug, Clone)]
pub enum Token {