Implement NativeFloat numbers
This commit is contained in:
parent
e526493b0e
commit
32234ad13b
142
src/main.rs
142
src/main.rs
@ -21,13 +21,14 @@ mod numbers;
|
|||||||
mod stv;
|
mod stv;
|
||||||
|
|
||||||
use crate::election::{Candidate, CandidateState, CountCard, CountState, CountStateOrRef, Election, StageResult};
|
use crate::election::{Candidate, CandidateState, CountCard, CountState, CountStateOrRef, Election, StageResult};
|
||||||
use crate::numbers::{Number, NumType};
|
use crate::numbers::{NativeFloat, Number, Rational};
|
||||||
|
|
||||||
use clap::Clap;
|
use clap::Clap;
|
||||||
use git_version::git_version;
|
use git_version::git_version;
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{self, BufRead};
|
use std::io::{self, BufRead};
|
||||||
|
use std::ops;
|
||||||
|
|
||||||
const VERSION: &str = git_version!(args=["--always", "--dirty=-dev"], fallback="unknown");
|
const VERSION: &str = git_version!(args=["--always", "--dirty=-dev"], fallback="unknown");
|
||||||
|
|
||||||
@ -49,6 +50,9 @@ enum Command {
|
|||||||
struct STV {
|
struct STV {
|
||||||
/// Path to the BLT file to be counted
|
/// Path to the BLT file to be counted
|
||||||
filename: String,
|
filename: String,
|
||||||
|
/// Numbers mode
|
||||||
|
#[clap(short, long, possible_values(&["rational", "native"]), default_value="rational")]
|
||||||
|
numbers: String,
|
||||||
/// Hide excluded candidates from results report
|
/// Hide excluded candidates from results report
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
hide_excluded: bool,
|
hide_excluded: bool,
|
||||||
@ -60,66 +64,6 @@ struct STV {
|
|||||||
pp_decimals: usize,
|
pp_decimals: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_candidates<'a, N: 'a + Number, I: Iterator<Item=(&'a Candidate, &'a CountCard<'a, N>)>>(candidates: I, cmd_opts: &STV) {
|
|
||||||
for (candidate, count_card) in candidates {
|
|
||||||
if count_card.state == CandidateState::ELECTED {
|
|
||||||
println!("- {}: {:.dps$} ({:.dps$}) - ELECTED {}", candidate.name, count_card.votes, count_card.transfers, count_card.order_elected, dps=cmd_opts.pp_decimals);
|
|
||||||
} else if count_card.state == CandidateState::EXCLUDED {
|
|
||||||
// If --hide-excluded, hide unless nonzero votes or nonzero transfers
|
|
||||||
if !cmd_opts.hide_excluded || !count_card.votes.is_zero() || !count_card.transfers.is_zero() {
|
|
||||||
println!("- {}: {:.dps$} ({:.dps$}) - Excluded {}", candidate.name, count_card.votes, count_card.transfers, -count_card.order_elected, dps=cmd_opts.pp_decimals);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("- {}: {:.dps$} ({:.dps$})", candidate.name, count_card.votes, count_card.transfers, dps=cmd_opts.pp_decimals);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_stage<N: Number>(stage_num: usize, result: &StageResult<N>, cmd_opts: &STV) {
|
|
||||||
// Print stage details
|
|
||||||
match result.kind {
|
|
||||||
None => { println!("{}. {}", stage_num, result.title); }
|
|
||||||
Some(kind) => { println!("{}. {} {}", stage_num, kind, result.title); }
|
|
||||||
};
|
|
||||||
println!("{}", result.logs.join(" "));
|
|
||||||
|
|
||||||
let state = result.state.as_ref();
|
|
||||||
|
|
||||||
// Print candidates
|
|
||||||
if cmd_opts.sort_votes {
|
|
||||||
// Sort by votes if requested
|
|
||||||
let mut candidates: Vec<(&Candidate, &CountCard<N>)> = state.candidates.iter()
|
|
||||||
.map(|(c, cc)| (*c, cc)).collect();
|
|
||||||
// First sort by order of election (as a tie-breaker, if votes are equal)
|
|
||||||
candidates.sort_unstable_by(|a, b| b.1.order_elected.partial_cmp(&a.1.order_elected).unwrap());
|
|
||||||
// Then sort by votes
|
|
||||||
candidates.sort_by(|a, b| a.1.votes.partial_cmp(&b.1.votes).unwrap());
|
|
||||||
print_candidates(candidates.into_iter().rev(), cmd_opts);
|
|
||||||
} else {
|
|
||||||
let candidates = state.election.candidates.iter()
|
|
||||||
.map(|c| (c, state.candidates.get(c).unwrap()));
|
|
||||||
print_candidates(candidates, cmd_opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print summary rows
|
|
||||||
println!("Exhausted: {:.dps$} ({:.dps$})", state.exhausted.votes, state.exhausted.transfers, dps=cmd_opts.pp_decimals);
|
|
||||||
println!("Loss by fraction: {:.dps$} ({:.dps$})", state.loss_fraction.votes, state.loss_fraction.transfers, dps=cmd_opts.pp_decimals);
|
|
||||||
|
|
||||||
println!("Quota: {:.dps$}", state.quota, dps=cmd_opts.pp_decimals);
|
|
||||||
|
|
||||||
println!("");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_and_print_result<N: Number>(stage_num: usize, state: &CountState<N>, cmd_opts: &STV) {
|
|
||||||
let result = StageResult {
|
|
||||||
kind: state.kind,
|
|
||||||
title: &state.title,
|
|
||||||
logs: state.logger.render(),
|
|
||||||
state: CountStateOrRef::from(&state),
|
|
||||||
};
|
|
||||||
print_stage(stage_num, &result, &cmd_opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Read arguments
|
// Read arguments
|
||||||
let opts: Opts = Opts::parse();
|
let opts: Opts = Opts::parse();
|
||||||
@ -128,8 +72,22 @@ fn main() {
|
|||||||
// Read BLT file
|
// Read BLT file
|
||||||
let file = File::open(&cmd_opts.filename).expect("IO Error");
|
let file = File::open(&cmd_opts.filename).expect("IO Error");
|
||||||
let lines = io::BufReader::new(file).lines();
|
let lines = io::BufReader::new(file).lines();
|
||||||
let election: Election<NumType> = Election::from_blt(lines);
|
|
||||||
|
|
||||||
|
// Create and count election according to --numbers
|
||||||
|
if cmd_opts.numbers == "rational" {
|
||||||
|
let election: Election<Rational> = Election::from_blt(lines);
|
||||||
|
count_election(election, cmd_opts);
|
||||||
|
} else if cmd_opts.numbers == "native" {
|
||||||
|
let election: Election<NativeFloat> = Election::from_blt(lines);
|
||||||
|
count_election(election, cmd_opts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_election<N: Number>(election: Election<N>, cmd_opts: STV)
|
||||||
|
where
|
||||||
|
for<'r> &'r N: ops::Sub<&'r N, Output=N>,
|
||||||
|
for<'r> &'r N: ops::Neg<Output=N>
|
||||||
|
{
|
||||||
// Initialise count state
|
// Initialise count state
|
||||||
let mut state = CountState::new(&election);
|
let mut state = CountState::new(&election);
|
||||||
|
|
||||||
@ -197,3 +155,63 @@ fn main() {
|
|||||||
println!("{}. {}", i + 1, winner.name);
|
println!("{}. {}", i + 1, winner.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn print_candidates<'a, N: 'a + Number, I: Iterator<Item=(&'a Candidate, &'a CountCard<'a, N>)>>(candidates: I, cmd_opts: &STV) {
|
||||||
|
for (candidate, count_card) in candidates {
|
||||||
|
if count_card.state == CandidateState::ELECTED {
|
||||||
|
println!("- {}: {:.dps$} ({:.dps$}) - ELECTED {}", candidate.name, count_card.votes, count_card.transfers, count_card.order_elected, dps=cmd_opts.pp_decimals);
|
||||||
|
} else if count_card.state == CandidateState::EXCLUDED {
|
||||||
|
// If --hide-excluded, hide unless nonzero votes or nonzero transfers
|
||||||
|
if !cmd_opts.hide_excluded || !count_card.votes.is_zero() || !count_card.transfers.is_zero() {
|
||||||
|
println!("- {}: {:.dps$} ({:.dps$}) - Excluded {}", candidate.name, count_card.votes, count_card.transfers, -count_card.order_elected, dps=cmd_opts.pp_decimals);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("- {}: {:.dps$} ({:.dps$})", candidate.name, count_card.votes, count_card.transfers, dps=cmd_opts.pp_decimals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_stage<N: Number>(stage_num: usize, result: &StageResult<N>, cmd_opts: &STV) {
|
||||||
|
// Print stage details
|
||||||
|
match result.kind {
|
||||||
|
None => { println!("{}. {}", stage_num, result.title); }
|
||||||
|
Some(kind) => { println!("{}. {} {}", stage_num, kind, result.title); }
|
||||||
|
};
|
||||||
|
println!("{}", result.logs.join(" "));
|
||||||
|
|
||||||
|
let state = result.state.as_ref();
|
||||||
|
|
||||||
|
// Print candidates
|
||||||
|
if cmd_opts.sort_votes {
|
||||||
|
// Sort by votes if requested
|
||||||
|
let mut candidates: Vec<(&Candidate, &CountCard<N>)> = state.candidates.iter()
|
||||||
|
.map(|(c, cc)| (*c, cc)).collect();
|
||||||
|
// First sort by order of election (as a tie-breaker, if votes are equal)
|
||||||
|
candidates.sort_unstable_by(|a, b| b.1.order_elected.partial_cmp(&a.1.order_elected).unwrap());
|
||||||
|
// Then sort by votes
|
||||||
|
candidates.sort_by(|a, b| a.1.votes.partial_cmp(&b.1.votes).unwrap());
|
||||||
|
print_candidates(candidates.into_iter().rev(), cmd_opts);
|
||||||
|
} else {
|
||||||
|
let candidates = state.election.candidates.iter()
|
||||||
|
.map(|c| (c, state.candidates.get(c).unwrap()));
|
||||||
|
print_candidates(candidates, cmd_opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print summary rows
|
||||||
|
println!("Exhausted: {:.dps$} ({:.dps$})", state.exhausted.votes, state.exhausted.transfers, dps=cmd_opts.pp_decimals);
|
||||||
|
println!("Loss by fraction: {:.dps$} ({:.dps$})", state.loss_fraction.votes, state.loss_fraction.transfers, dps=cmd_opts.pp_decimals);
|
||||||
|
|
||||||
|
println!("Quota: {:.dps$}", state.quota, dps=cmd_opts.pp_decimals);
|
||||||
|
|
||||||
|
println!("");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_and_print_result<N: Number>(stage_num: usize, state: &CountState<N>, cmd_opts: &STV) {
|
||||||
|
let result = StageResult {
|
||||||
|
kind: state.kind,
|
||||||
|
title: &state.title,
|
||||||
|
logs: state.logger.render(),
|
||||||
|
state: CountStateOrRef::from(&state),
|
||||||
|
};
|
||||||
|
print_stage(stage_num, &result, &cmd_opts);
|
||||||
|
}
|
||||||
|
45
src/numbers/mod.rs
Normal file
45
src/numbers/mod.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/* OpenTally: Open-source election vote counting
|
||||||
|
* Copyright © 2021 Lee Yingtong Li (RunasSudo)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
mod native;
|
||||||
|
mod rational;
|
||||||
|
|
||||||
|
use num_traits::{NumAssignRef, NumRef};
|
||||||
|
use rug::{self, Assign};
|
||||||
|
|
||||||
|
use std::cmp::{PartialOrd};
|
||||||
|
use std::fmt;
|
||||||
|
use std::ops;
|
||||||
|
|
||||||
|
//pub trait Number: NumRef + NumAssignRef + PartialOrd + Assign + Clone + fmt::Display where for<'a> &'a Self: RefNum<&'a Self> {
|
||||||
|
pub trait Number: NumRef + NumAssignRef + ops::Neg<Output=Self> + PartialOrd + Assign + Clone + fmt::Display where for<'a> Self: Assign<&'a Self>{
|
||||||
|
fn new() -> Self;
|
||||||
|
fn from(n: usize) -> Self;
|
||||||
|
|
||||||
|
fn floor_mut(&mut self);
|
||||||
|
|
||||||
|
fn parse(s: &str) -> Self {
|
||||||
|
if let Ok(value) = Self::from_str_radix(s, 10) {
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
panic!("Syntax Error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use self::native::NativeFloat;
|
||||||
|
pub use self::rational::Rational;
|
264
src/numbers/native.rs
Normal file
264
src/numbers/native.rs
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
/* OpenTally: Open-source election vote counting
|
||||||
|
* Copyright © 2021 Lee Yingtong Li (RunasSudo)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use super::Number;
|
||||||
|
|
||||||
|
use num_traits::{Num, One, Zero};
|
||||||
|
use rug::Assign;
|
||||||
|
|
||||||
|
use std::cmp::{Ordering, PartialEq, PartialOrd};
|
||||||
|
use std::num::ParseIntError;
|
||||||
|
use std::fmt;
|
||||||
|
use std::ops;
|
||||||
|
|
||||||
|
pub struct NativeFloat(f32);
|
||||||
|
|
||||||
|
impl Number for NativeFloat {
|
||||||
|
fn new() -> Self { Self(0.0) }
|
||||||
|
|
||||||
|
fn from(n: usize) -> Self { Self(n as f32) }
|
||||||
|
|
||||||
|
fn floor_mut(&mut self) { self.0 = self.0.floor() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Num for NativeFloat {
|
||||||
|
type FromStrRadixErr = ParseIntError;
|
||||||
|
|
||||||
|
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
|
||||||
|
match i32::from_str_radix(str, radix) {
|
||||||
|
Ok(value) => Ok(Self(value as f32)),
|
||||||
|
Err(err) => Err(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Assign for NativeFloat {
|
||||||
|
fn assign(&mut self, src: Self) { self.0 = src.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Assign<&NativeFloat> for NativeFloat {
|
||||||
|
fn assign(&mut self, src: &NativeFloat) { self.0 = src.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for NativeFloat {
|
||||||
|
fn clone(&self) -> Self { Self(self.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for NativeFloat {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl One for NativeFloat {
|
||||||
|
fn one() -> Self { Self(1.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Zero for NativeFloat {
|
||||||
|
fn zero() -> Self { Self::new() }
|
||||||
|
fn is_zero(&self) -> bool { self.0.is_zero() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for NativeFloat {
|
||||||
|
fn eq(&self, _other: &Self) -> bool {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for NativeFloat {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { self.0.partial_cmp(&other.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Neg for NativeFloat {
|
||||||
|
type Output = NativeFloat;
|
||||||
|
fn neg(self) -> Self::Output { Self(-self.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Add for NativeFloat {
|
||||||
|
type Output = NativeFloat;
|
||||||
|
fn add(self, _rhs: Self) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Sub for NativeFloat {
|
||||||
|
type Output = NativeFloat;
|
||||||
|
fn sub(self, _rhs: Self) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Mul for NativeFloat {
|
||||||
|
type Output = NativeFloat;
|
||||||
|
fn mul(self, _rhs: Self) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Div for NativeFloat {
|
||||||
|
type Output = NativeFloat;
|
||||||
|
fn div(self, _rhs: Self) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Rem for NativeFloat {
|
||||||
|
type Output = NativeFloat;
|
||||||
|
|
||||||
|
fn rem(self, _rhs: Self) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Add<&NativeFloat> for NativeFloat {
|
||||||
|
type Output = NativeFloat;
|
||||||
|
fn add(self, rhs: &NativeFloat) -> Self::Output { Self(self.0 + &rhs.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Sub<&NativeFloat> for NativeFloat {
|
||||||
|
type Output = NativeFloat;
|
||||||
|
fn sub(self, _rhs: &NativeFloat) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Mul<&NativeFloat> for NativeFloat {
|
||||||
|
type Output = NativeFloat;
|
||||||
|
fn mul(self, rhs: &NativeFloat) -> Self::Output { NativeFloat(self.0 * &rhs.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Div<&NativeFloat> for NativeFloat {
|
||||||
|
type Output = NativeFloat;
|
||||||
|
fn div(self, rhs: &NativeFloat) -> Self::Output { NativeFloat(self.0 / &rhs.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Rem<&NativeFloat> for NativeFloat {
|
||||||
|
type Output = NativeFloat;
|
||||||
|
fn rem(self, _rhs: &NativeFloat) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::AddAssign for NativeFloat {
|
||||||
|
fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::SubAssign for NativeFloat {
|
||||||
|
fn sub_assign(&mut self, rhs: Self) { self.0 -= rhs.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::MulAssign for NativeFloat {
|
||||||
|
fn mul_assign(&mut self, _rhs: Self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::DivAssign for NativeFloat {
|
||||||
|
fn div_assign(&mut self, rhs: Self) {
|
||||||
|
self.0 /= &rhs.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::RemAssign for NativeFloat {
|
||||||
|
fn rem_assign(&mut self, _rhs: Self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::AddAssign<&NativeFloat> for NativeFloat {
|
||||||
|
fn add_assign(&mut self, rhs: &NativeFloat) { self.0 += &rhs.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::SubAssign<&NativeFloat> for NativeFloat {
|
||||||
|
fn sub_assign(&mut self, rhs: &NativeFloat) { self.0 -= &rhs.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::MulAssign<&NativeFloat> for NativeFloat {
|
||||||
|
fn mul_assign(&mut self, _rhs: &NativeFloat) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::DivAssign<&NativeFloat> for NativeFloat {
|
||||||
|
fn div_assign(&mut self, _rhs: &NativeFloat) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::RemAssign<&NativeFloat> for NativeFloat {
|
||||||
|
fn rem_assign(&mut self, _rhs: &NativeFloat) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Neg for &NativeFloat {
|
||||||
|
type Output = NativeFloat;
|
||||||
|
fn neg(self) -> Self::Output { NativeFloat(-&self.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Add<&NativeFloat> for &NativeFloat {
|
||||||
|
type Output = NativeFloat;
|
||||||
|
fn add(self, _rhs: &NativeFloat) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Sub<&NativeFloat> for &NativeFloat {
|
||||||
|
type Output = NativeFloat;
|
||||||
|
fn sub(self, rhs: &NativeFloat) -> Self::Output { NativeFloat(&self.0 - &rhs.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Mul<&NativeFloat> for &NativeFloat {
|
||||||
|
type Output = NativeFloat;
|
||||||
|
fn mul(self, _rhs: &NativeFloat) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Div<&NativeFloat> for &NativeFloat {
|
||||||
|
type Output = NativeFloat;
|
||||||
|
fn div(self, _rhs: &NativeFloat) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Rem<&NativeFloat> for &NativeFloat {
|
||||||
|
type Output = NativeFloat;
|
||||||
|
fn rem(self, _rhs: &NativeFloat) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
impl ops::Add<&&NativeFloat> for &NativeFloat {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Sub<&&NativeFloat> for &NativeFloat {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Mul<&&NativeFloat> for &NativeFloat {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Div<&&NativeFloat> for &NativeFloat {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Rem<&&NativeFloat> for &NativeFloat {
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
@ -15,30 +15,15 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use num_traits::{Num, NumAssignRef, NumRef, One, Zero};
|
use super::Number;
|
||||||
|
|
||||||
|
use num_traits::{Num, One, Zero};
|
||||||
use rug::{self, Assign, ops::Pow, rational::ParseRationalError};
|
use rug::{self, Assign, ops::Pow, rational::ParseRationalError};
|
||||||
|
|
||||||
use std::cmp::{Ordering, PartialEq, PartialOrd};
|
use std::cmp::{Ordering, PartialEq, PartialOrd};
|
||||||
use std::convert::TryInto;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops;
|
use std::ops;
|
||||||
|
|
||||||
//pub trait Number: NumRef + NumAssignRef + PartialOrd + Assign + Clone + fmt::Display where for<'a> &'a Self: RefNum<&'a Self> {
|
|
||||||
pub trait Number: NumRef + NumAssignRef + ops::Neg<Output=Self> + PartialOrd + Assign + Clone + fmt::Display where for<'a> Self: Assign<&'a Self>{
|
|
||||||
fn new() -> Self;
|
|
||||||
fn from(n: usize) -> Self;
|
|
||||||
|
|
||||||
fn floor_mut(&mut self);
|
|
||||||
|
|
||||||
fn parse(s: &str) -> Self {
|
|
||||||
if let Ok(value) = Self::from_str_radix(s, 10) {
|
|
||||||
return value;
|
|
||||||
} else {
|
|
||||||
panic!("Syntax Error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Rational(rug::Rational);
|
pub struct Rational(rug::Rational);
|
||||||
|
|
||||||
impl Number for Rational {
|
impl Number for Rational {
|
||||||
@ -53,7 +38,7 @@ impl Num for Rational {
|
|||||||
type FromStrRadixErr = ParseRationalError;
|
type FromStrRadixErr = ParseRationalError;
|
||||||
|
|
||||||
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
|
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
|
||||||
match rug::Rational::parse_radix(str, radix.try_into().unwrap()) {
|
match rug::Rational::parse_radix(str, radix as i32) {
|
||||||
Ok(value) => Ok(Self(rug::Rational::from(value))),
|
Ok(value) => Ok(Self(rug::Rational::from(value))),
|
||||||
Err(err) => Err(err)
|
Err(err) => Err(err)
|
||||||
}
|
}
|
||||||
@ -97,7 +82,7 @@ impl fmt::Display for Rational {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl One for Rational {
|
impl One for Rational {
|
||||||
fn one() -> Self { Rational(rug::Rational::from(1)) }
|
fn one() -> Self { Self(rug::Rational::from(1)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Zero for Rational {
|
impl Zero for Rational {
|
||||||
@ -117,7 +102,7 @@ impl PartialOrd for Rational {
|
|||||||
|
|
||||||
impl ops::Neg for Rational {
|
impl ops::Neg for Rational {
|
||||||
type Output = Rational;
|
type Output = Rational;
|
||||||
fn neg(self) -> Self::Output { Rational(-self.0) }
|
fn neg(self) -> Self::Output { Self(-self.0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ops::Add for Rational {
|
impl ops::Add for Rational {
|
||||||
@ -158,7 +143,7 @@ impl ops::Rem for Rational {
|
|||||||
|
|
||||||
impl ops::Add<&Rational> for Rational {
|
impl ops::Add<&Rational> for Rational {
|
||||||
type Output = Rational;
|
type Output = Rational;
|
||||||
fn add(self, rhs: &Rational) -> Self::Output { Rational(self.0 + &rhs.0) }
|
fn add(self, rhs: &Rational) -> Self::Output { Self(self.0 + &rhs.0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ops::Sub<&Rational> for Rational {
|
impl ops::Sub<&Rational> for Rational {
|
||||||
@ -170,12 +155,12 @@ impl ops::Sub<&Rational> for Rational {
|
|||||||
|
|
||||||
impl ops::Mul<&Rational> for Rational {
|
impl ops::Mul<&Rational> for Rational {
|
||||||
type Output = Rational;
|
type Output = Rational;
|
||||||
fn mul(self, rhs: &Rational) -> Self::Output { Rational(self.0 * &rhs.0) }
|
fn mul(self, rhs: &Rational) -> Self::Output { Self(self.0 * &rhs.0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ops::Div<&Rational> for Rational {
|
impl ops::Div<&Rational> for Rational {
|
||||||
type Output = Rational;
|
type Output = Rational;
|
||||||
fn div(self, rhs: &Rational) -> Self::Output { Rational(self.0 / &rhs.0) }
|
fn div(self, rhs: &Rational) -> Self::Output { Self(self.0 / &rhs.0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ops::Rem<&Rational> for Rational {
|
impl ops::Rem<&Rational> for Rational {
|
||||||
@ -251,9 +236,7 @@ impl ops::Add<&Rational> for &Rational {
|
|||||||
|
|
||||||
impl ops::Sub<&Rational> for &Rational {
|
impl ops::Sub<&Rational> for &Rational {
|
||||||
type Output = Rational;
|
type Output = Rational;
|
||||||
fn sub(self, rhs: &Rational) -> Self::Output {
|
fn sub(self, rhs: &Rational) -> Self::Output { Rational(rug::Rational::from(&self.0 - &rhs.0)) }
|
||||||
return Rational(rug::Rational::from(&self.0 - &rhs.0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ops::Mul<&Rational> for &Rational {
|
impl ops::Mul<&Rational> for &Rational {
|
||||||
@ -298,5 +281,3 @@ impl ops::Rem<&&Rational> for &Rational {
|
|||||||
|
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub type NumType = Rational;
|
|
Loading…
Reference in New Issue
Block a user