Implement --numbers fixed
This commit is contained in:
parent
441e266b17
commit
ceba059c53
60
Cargo.lock
generated
60
Cargo.lock
generated
@ -96,6 +96,18 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const_fn_assert"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27d614f23f34f7b5165a77dc1591f497e2518f9cec4b4f4b92bfc4dc6cf7a190"
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.2.1"
|
||||
@ -127,6 +139,18 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "0.99.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cc7b9cef1e351660e5443924e4f43ab25fbbed3e9a5f052df3677deb4d6b320"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.20"
|
||||
@ -186,6 +210,19 @@ dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ibig"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61c5022ee7f7a2feb0bd2fdc4b8ec882cd14903cebf33e7c1847e3f3a282f8b7"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"const_fn_assert",
|
||||
"num-traits",
|
||||
"rand",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.6.2"
|
||||
@ -297,8 +334,10 @@ dependencies = [
|
||||
"clap",
|
||||
"console_error_panic_hook",
|
||||
"csv",
|
||||
"derive_more",
|
||||
"flate2",
|
||||
"git-version",
|
||||
"ibig",
|
||||
"js-sys",
|
||||
"num-bigint",
|
||||
"num-rational",
|
||||
@ -368,6 +407,21 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.9"
|
||||
@ -400,6 +454,12 @@ version = "1.0.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.72"
|
||||
|
@ -8,7 +8,9 @@ edition = "2018"
|
||||
crate-type = ["lib", "cdylib"]
|
||||
|
||||
[dependencies]
|
||||
derive_more = "0.99.14"
|
||||
git-version = "0.3.4"
|
||||
ibig = "0.3.2"
|
||||
num-traits = "0.2"
|
||||
wasm-bindgen = "0.2.74"
|
||||
|
||||
|
@ -146,18 +146,16 @@
|
||||
<label>
|
||||
Numbers:
|
||||
<select id="selNumbers">
|
||||
<!--<option value="native">Native</option>
|
||||
<option value="rational">Rational</option>
|
||||
<option value="fixed" selected>Fixed</option>
|
||||
<option value="gfixed">Fixed (guarded)</option>-->
|
||||
<option value="rational">Rational</option>
|
||||
<!--<option value="gfixed">Fixed (guarded)</option>-->
|
||||
<option value="float64">Float (64-bit)</option>
|
||||
</select>
|
||||
</label>
|
||||
<!--<label>
|
||||
Decimal places (if Numbers = Fixed):
|
||||
<label>
|
||||
Decimal places (if <i>Numbers</i> = <i>Fixed</i>):
|
||||
<input type="number" id="txtDP" value="5" min="0" style="width: 3em;">
|
||||
</label>-->
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label>
|
||||
|
@ -99,5 +99,6 @@ async function clickCount() {
|
||||
'optsStr': optsStr,
|
||||
'filePath': filePath,
|
||||
'numbers': document.getElementById('selNumbers').value,
|
||||
'decimals': document.getElementById('txtDP').value,
|
||||
});
|
||||
}
|
||||
|
@ -11,10 +11,15 @@ initWasm();
|
||||
onmessage = function(evt) {
|
||||
if (evt.data.type === 'countElection') {
|
||||
let numbers;
|
||||
if (evt.data.numbers === 'rational') {
|
||||
numbers = 'Rational';
|
||||
if (evt.data.numbers === 'fixed') {
|
||||
numbers = 'Fixed';
|
||||
wasm.fixed_set_dps(evt.data.decimals);
|
||||
} else if (evt.data.numbers === 'float64') {
|
||||
numbers = 'NativeFloat64';
|
||||
} else if (evt.data.numbers === 'rational') {
|
||||
numbers = 'Rational';
|
||||
} else {
|
||||
throw 'Unknown --numbers';
|
||||
}
|
||||
|
||||
// Init election
|
||||
|
12
src/main.rs
12
src/main.rs
@ -17,7 +17,7 @@
|
||||
|
||||
use opentally::stv;
|
||||
use opentally::election::{Candidate, CandidateState, CountCard, CountState, CountStateOrRef, Election, StageResult};
|
||||
use opentally::numbers::{NativeFloat64, Number, Rational};
|
||||
use opentally::numbers::{Fixed, NativeFloat64, Number, Rational};
|
||||
|
||||
use clap::{AppSettings, Clap};
|
||||
|
||||
@ -52,9 +52,13 @@ struct STV {
|
||||
// -- Numbers settings --
|
||||
|
||||
/// Numbers mode
|
||||
#[clap(help_heading=Some("NUMBERS"), short, long, possible_values=&["rational", "float64"], default_value="rational", value_name="mode")]
|
||||
#[clap(help_heading=Some("NUMBERS"), short, long, possible_values=&["rational", "float64", "fixed"], default_value="rational", value_name="mode")]
|
||||
numbers: String,
|
||||
|
||||
/// Decimal places if --numbers fixed
|
||||
#[clap(help_heading=Some("NUMBERS"), long, default_value="5", value_name="dps")]
|
||||
decimals: usize,
|
||||
|
||||
// -----------------------
|
||||
// -- Rounding settings --
|
||||
|
||||
@ -135,6 +139,10 @@ fn main() {
|
||||
} else if cmd_opts.numbers == "float64" {
|
||||
let election: Election<NativeFloat64> = Election::from_blt(lines.map(|r| r.expect("IO Error").to_string()).into_iter());
|
||||
count_election(election, cmd_opts);
|
||||
} else if cmd_opts.numbers == "fixed" {
|
||||
Fixed::set_dps(cmd_opts.decimals);
|
||||
let election: Election<Fixed> = Election::from_blt(lines.map(|r| r.expect("IO Error").to_string()).into_iter());
|
||||
count_election(election, cmd_opts);
|
||||
}
|
||||
}
|
||||
|
||||
|
327
src/numbers/fixed.rs
Normal file
327
src/numbers/fixed.rs
Normal file
@ -0,0 +1,327 @@
|
||||
/* 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::{Assign, From, Number};
|
||||
|
||||
use ibig::{IBig, ops::Abs};
|
||||
use num_traits::{Num, One, Zero};
|
||||
|
||||
use std::cmp::{Ord, PartialEq, PartialOrd};
|
||||
use std::ops;
|
||||
use std::fmt;
|
||||
|
||||
static mut DPS: Option<usize> = None;
|
||||
static mut FACTOR: Option<IBig> = None;
|
||||
|
||||
#[inline]
|
||||
pub fn get_dps() -> usize {
|
||||
unsafe { DPS.unwrap() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_factor() -> &'static IBig {
|
||||
unsafe { FACTOR.as_ref().unwrap() }
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, Ord, PartialEq, PartialOrd)]
|
||||
pub struct Fixed(IBig);
|
||||
|
||||
impl Fixed {
|
||||
pub fn set_dps(dps: usize) {
|
||||
unsafe {
|
||||
DPS = Some(dps);
|
||||
FACTOR = Some(IBig::from(10).pow(dps));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Number for Fixed {
|
||||
fn new() -> Self { Self(IBig::zero()) }
|
||||
|
||||
fn describe() -> String { format!("--numbers fixed --decimals {}", get_dps()) }
|
||||
|
||||
fn pow_assign(&mut self, exponent: i32) {
|
||||
self.0 = self.0.pow(exponent as usize) * get_factor() / get_factor().pow(exponent as usize);
|
||||
}
|
||||
|
||||
fn floor_mut(&mut self, dps: usize) {
|
||||
// Only do something if truncating
|
||||
if dps < get_dps() {
|
||||
let factor = IBig::from(10).pow(get_dps() - dps);
|
||||
self.0 /= &factor;
|
||||
self.0 *= factor;
|
||||
}
|
||||
}
|
||||
|
||||
fn ceil_mut(&mut self, dps: usize) {
|
||||
// Only do something if truncating
|
||||
if dps < get_dps() {
|
||||
self.0 += IBig::one();
|
||||
let factor = IBig::from(10).pow(get_dps() - dps);
|
||||
self.0 /= &factor;
|
||||
self.0 *= factor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Num for Fixed {
|
||||
type FromStrRadixErr = ibig::error::ParseError;
|
||||
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
|
||||
match IBig::from_str_radix(str, radix) {
|
||||
Ok(value) => Ok(Self(value * get_factor())),
|
||||
Err(err) => Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Assign for Fixed {
|
||||
fn assign(&mut self, src: Self) { self.0 = src.0 }
|
||||
}
|
||||
|
||||
impl Assign<&Self> for Fixed {
|
||||
fn assign(&mut self, src: &Self) { self.0 = src.0.clone() }
|
||||
}
|
||||
|
||||
impl From<usize> for Fixed {
|
||||
fn from(n: usize) -> Self { Self(IBig::from(n) * get_factor()) }
|
||||
}
|
||||
|
||||
impl From<f64> for Fixed {
|
||||
fn from(n: f64) -> Self {
|
||||
return Self(IBig::from((n * 10_f64.powi(get_dps() as i32)) as u32))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Fixed {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let dps = match f.precision() {
|
||||
Some(precision) => if precision < get_dps() { precision } else { get_dps() },
|
||||
None => get_dps(),
|
||||
};
|
||||
|
||||
let factor = IBig::from(10).pow(get_dps() - dps);
|
||||
let mut result = (&self.0 / factor).abs().to_string();
|
||||
|
||||
let should_add_minus = (self.0 < IBig::zero()) && result != "0";
|
||||
|
||||
// Add leading 0s
|
||||
result = format!("{0:0>1$}", result, dps + 1);
|
||||
|
||||
// Add the decimal point
|
||||
if dps > 0 {
|
||||
result.insert(result.len() - dps, '.');
|
||||
}
|
||||
|
||||
// Add the sign
|
||||
if should_add_minus {
|
||||
result.insert(0, '-');
|
||||
}
|
||||
|
||||
return f.write_str(&result);
|
||||
}
|
||||
}
|
||||
|
||||
impl One for Fixed {
|
||||
fn one() -> Self { Self(get_factor().clone()) }
|
||||
}
|
||||
|
||||
impl Zero for Fixed {
|
||||
fn zero() -> Self { Self::new() }
|
||||
fn is_zero(&self) -> bool { self.0.is_zero() }
|
||||
}
|
||||
|
||||
impl ops::Neg for Fixed {
|
||||
type Output = Self;
|
||||
fn neg(self) -> Self::Output { Self(-self.0) }
|
||||
}
|
||||
|
||||
impl ops::Add for Fixed {
|
||||
type Output = Self;
|
||||
fn add(self, _rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Sub for Fixed {
|
||||
type Output = Self;
|
||||
fn sub(self, _rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Mul for Fixed {
|
||||
type Output = Self;
|
||||
fn mul(self, _rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Div for Fixed {
|
||||
type Output = Self;
|
||||
fn div(self, _rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Rem for Fixed {
|
||||
type Output = Self;
|
||||
fn rem(self, _rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Add<&Self> for Fixed {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: &Self) -> Self::Output { Self(self.0 + &rhs.0) }
|
||||
}
|
||||
|
||||
impl ops::Sub<&Self> for Fixed {
|
||||
type Output = Self;
|
||||
fn sub(self, _rhs: &Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Mul<&Self> for Fixed {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: &Self) -> Self::Output { Self(self.0 * &rhs.0 / get_factor()) }
|
||||
}
|
||||
|
||||
impl ops::Div<&Self> for Fixed {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: &Self) -> Self::Output { Self(self.0 * get_factor() / &rhs.0) }
|
||||
}
|
||||
|
||||
impl ops::Rem<&Self> for Fixed {
|
||||
type Output = Self;
|
||||
fn rem(self, _rhs: &Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::AddAssign for Fixed {
|
||||
fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0; }
|
||||
}
|
||||
|
||||
impl ops::SubAssign for Fixed {
|
||||
fn sub_assign(&mut self, rhs: Self) { self.0 -= rhs.0; }
|
||||
}
|
||||
|
||||
impl ops::MulAssign for Fixed {
|
||||
fn mul_assign(&mut self, rhs: Self) {
|
||||
self.0 *= rhs.0;
|
||||
self.0 /= get_factor();
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::DivAssign for Fixed {
|
||||
fn div_assign(&mut self, rhs: Self) {
|
||||
self.0 *= get_factor();
|
||||
self.0 /= rhs.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::RemAssign for Fixed {
|
||||
fn rem_assign(&mut self, _rhs: Self) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::AddAssign<&Self> for Fixed {
|
||||
fn add_assign(&mut self, rhs: &Self) { self.0 += &rhs.0; }
|
||||
}
|
||||
|
||||
impl ops::SubAssign<&Self> for Fixed {
|
||||
fn sub_assign(&mut self, rhs: &Self) { self.0 -= &rhs.0; }
|
||||
}
|
||||
|
||||
impl ops::MulAssign<&Self> for Fixed {
|
||||
fn mul_assign(&mut self, rhs: &Self) {
|
||||
self.0 *= &rhs.0;
|
||||
self.0 /= get_factor();
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::DivAssign<&Self> for Fixed {
|
||||
fn div_assign(&mut self, _rhs: &Self) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::RemAssign<&Self> for Fixed {
|
||||
fn rem_assign(&mut self, _rhs: &Self) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Neg for &Fixed {
|
||||
type Output = Fixed;
|
||||
fn neg(self) -> Self::Output { Fixed(-&self.0) }
|
||||
}
|
||||
|
||||
impl ops::Add<Self> for &Fixed {
|
||||
type Output = Fixed;
|
||||
fn add(self, _rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Sub<Self> for &Fixed {
|
||||
type Output = Fixed;
|
||||
fn sub(self, rhs: Self) -> Self::Output { Fixed(&self.0 - &rhs.0) }
|
||||
}
|
||||
|
||||
impl ops::Mul<Self> for &Fixed {
|
||||
type Output = Fixed;
|
||||
fn mul(self, _rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Div<Self> for &Fixed {
|
||||
type Output = Fixed;
|
||||
fn div(self, rhs: Self) -> Self::Output { Fixed(&self.0 * get_factor() / &rhs.0) }
|
||||
}
|
||||
|
||||
impl ops::Rem<Self> for &Fixed {
|
||||
type Output = Fixed;
|
||||
fn rem(self, _rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl ops::Add<&&Rational> for &Rational {
|
||||
|
||||
}
|
||||
|
||||
impl ops::Sub<&&Rational> for &Rational {
|
||||
|
||||
}
|
||||
|
||||
impl ops::Mul<&&Rational> for &Rational {
|
||||
|
||||
}
|
||||
|
||||
impl ops::Div<&&Rational> for &Rational {
|
||||
|
||||
}
|
||||
|
||||
impl ops::Rem<&&Rational> for &Rational {
|
||||
|
||||
}
|
||||
*/
|
@ -15,6 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
mod fixed;
|
||||
mod native;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
@ -60,6 +61,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub use self::fixed::Fixed;
|
||||
pub use self::native::NativeFloat64;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
|
@ -17,15 +17,16 @@
|
||||
|
||||
use super::{Assign, From, Number};
|
||||
|
||||
use derive_more::Display;
|
||||
use num_traits::{Num, One, Zero};
|
||||
|
||||
use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
|
||||
use std::num::ParseIntError;
|
||||
use std::fmt;
|
||||
use std::ops;
|
||||
|
||||
type ImplType = f64;
|
||||
|
||||
#[derive(Clone, Display, PartialEq, PartialOrd)]
|
||||
pub struct NativeFloat64(ImplType);
|
||||
|
||||
impl Number for NativeFloat64 {
|
||||
@ -50,7 +51,6 @@ impl Number for NativeFloat64 {
|
||||
|
||||
impl Num for NativeFloat64 {
|
||||
type FromStrRadixErr = ParseIntError;
|
||||
|
||||
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
|
||||
match i64::from_str_radix(str, radix) {
|
||||
Ok(value) => Ok(Self(value as ImplType)),
|
||||
@ -75,14 +75,6 @@ impl From<f64> for NativeFloat64 {
|
||||
fn from(n: f64) -> Self { Self(n as ImplType) }
|
||||
}
|
||||
|
||||
impl Clone for NativeFloat64 {
|
||||
fn clone(&self) -> Self { Self(self.0) }
|
||||
}
|
||||
|
||||
impl fmt::Display for NativeFloat64 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) }
|
||||
}
|
||||
|
||||
impl One for NativeFloat64 {
|
||||
fn one() -> Self { Self(1.0) }
|
||||
}
|
||||
@ -93,18 +85,10 @@ impl Zero for NativeFloat64 {
|
||||
}
|
||||
|
||||
impl Eq for NativeFloat64 {}
|
||||
impl PartialEq for NativeFloat64 {
|
||||
fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
|
||||
}
|
||||
|
||||
impl Ord for NativeFloat64 {
|
||||
fn cmp(&self, other: &Self) -> Ordering { self.0.partial_cmp(&other.0).unwrap() }
|
||||
}
|
||||
|
||||
impl PartialOrd for NativeFloat64 {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { self.0.partial_cmp(&other.0) }
|
||||
}
|
||||
|
||||
impl ops::Neg for NativeFloat64 {
|
||||
type Output = NativeFloat64;
|
||||
fn neg(self) -> Self::Output { Self(-self.0) }
|
||||
@ -140,7 +124,6 @@ impl ops::Div for NativeFloat64 {
|
||||
|
||||
impl ops::Rem for NativeFloat64 {
|
||||
type Output = NativeFloat64;
|
||||
|
||||
fn rem(self, _rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
|
||||
use std::fmt;
|
||||
use std::ops;
|
||||
|
||||
#[derive(Clone, PartialEq, PartialOrd)]
|
||||
pub struct Rational(BigRational);
|
||||
|
||||
impl Number for Rational {
|
||||
@ -60,11 +61,8 @@ impl Number for Rational {
|
||||
}
|
||||
|
||||
impl Num for Rational {
|
||||
//type FromStrRadixErr = ParseRatioError;
|
||||
type FromStrRadixErr = ParseBigIntError;
|
||||
|
||||
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
|
||||
//match BigRational::from_str_radix(str, radix) {
|
||||
match BigInt::from_str_radix(str, radix) {
|
||||
Ok(value) => Ok(Self(BigRational::from_integer(value))),
|
||||
Err(err) => Err(err)
|
||||
@ -91,10 +89,6 @@ impl From<f64> for Rational {
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Rational {
|
||||
fn clone(&self) -> Self { Self(self.0.clone()) }
|
||||
}
|
||||
|
||||
impl fmt::Display for Rational {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if let Some(precision) = f.precision() {
|
||||
@ -136,18 +130,10 @@ impl Zero for Rational {
|
||||
}
|
||||
|
||||
impl Eq for Rational {}
|
||||
impl PartialEq for Rational {
|
||||
fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
|
||||
}
|
||||
|
||||
impl Ord for Rational {
|
||||
fn cmp(&self, other: &Self) -> Ordering { self.0.partial_cmp(&other.0).unwrap() }
|
||||
}
|
||||
|
||||
impl PartialOrd for Rational {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { self.0.partial_cmp(&other.0) }
|
||||
}
|
||||
|
||||
impl ops::Neg for Rational {
|
||||
type Output = Rational;
|
||||
fn neg(self) -> Self::Output { Self(-self.0) }
|
||||
@ -183,7 +169,6 @@ impl ops::Div for Rational {
|
||||
|
||||
impl ops::Rem for Rational {
|
||||
type Output = Rational;
|
||||
|
||||
fn rem(self, _rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
|
||||
use std::fmt;
|
||||
use std::ops;
|
||||
|
||||
#[derive(Clone, PartialEq, PartialOrd)]
|
||||
pub struct Rational(rug::Rational);
|
||||
|
||||
impl Number for Rational {
|
||||
@ -61,7 +62,6 @@ impl Number for Rational {
|
||||
|
||||
impl Num for Rational {
|
||||
type FromStrRadixErr = ParseRationalError;
|
||||
|
||||
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
|
||||
match rug::Rational::parse_radix(str, radix as i32) {
|
||||
Ok(value) => Ok(Self(rug::Rational::from(value))),
|
||||
@ -74,8 +74,8 @@ impl Assign for Rational {
|
||||
fn assign(&mut self, src: Self) { self.0.assign(src.0) }
|
||||
}
|
||||
|
||||
impl Assign<&Rational> for Rational {
|
||||
fn assign(&mut self, src: &Rational) { self.0.assign(&src.0) }
|
||||
impl Assign<&Self> for Rational {
|
||||
fn assign(&mut self, src: &Self) { self.0.assign(&src.0) }
|
||||
}
|
||||
|
||||
impl From<usize> for Rational {
|
||||
@ -89,10 +89,6 @@ impl From<f64> for Rational {
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Rational {
|
||||
fn clone(&self) -> Self { Self(self.0.clone()) }
|
||||
}
|
||||
|
||||
impl fmt::Display for Rational {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if let Some(precision) = f.precision() {
|
||||
@ -134,84 +130,75 @@ impl Zero for Rational {
|
||||
}
|
||||
|
||||
impl Eq for Rational {}
|
||||
impl PartialEq for Rational {
|
||||
fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
|
||||
}
|
||||
|
||||
impl Ord for Rational {
|
||||
fn cmp(&self, other: &Self) -> Ordering { self.0.cmp(&other.0) }
|
||||
}
|
||||
|
||||
impl PartialOrd for Rational {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { self.0.partial_cmp(&other.0) }
|
||||
}
|
||||
|
||||
impl ops::Neg for Rational {
|
||||
type Output = Rational;
|
||||
type Output = Self;
|
||||
fn neg(self) -> Self::Output { Self(-self.0) }
|
||||
}
|
||||
|
||||
impl ops::Add for Rational {
|
||||
type Output = Rational;
|
||||
type Output = Self;
|
||||
fn add(self, _rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Sub for Rational {
|
||||
type Output = Rational;
|
||||
type Output = Self;
|
||||
fn sub(self, _rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Mul for Rational {
|
||||
type Output = Rational;
|
||||
type Output = Self;
|
||||
fn mul(self, _rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Div for Rational {
|
||||
type Output = Rational;
|
||||
type Output = Self;
|
||||
fn div(self, _rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Rem for Rational {
|
||||
type Output = Rational;
|
||||
|
||||
type Output = Self;
|
||||
fn rem(self, _rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Add<&Rational> for Rational {
|
||||
type Output = Rational;
|
||||
fn add(self, rhs: &Rational) -> Self::Output { Self(self.0 + &rhs.0) }
|
||||
impl ops::Add<&Self> for Rational {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: &Self) -> Self::Output { Self(self.0 + &rhs.0) }
|
||||
}
|
||||
|
||||
impl ops::Sub<&Rational> for Rational {
|
||||
type Output = Rational;
|
||||
fn sub(self, _rhs: &Rational) -> Self::Output {
|
||||
impl ops::Sub<&Self> for Rational {
|
||||
type Output = Self;
|
||||
fn sub(self, _rhs: &Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Mul<&Rational> for Rational {
|
||||
type Output = Rational;
|
||||
fn mul(self, rhs: &Rational) -> Self::Output { Self(self.0 * &rhs.0) }
|
||||
impl ops::Mul<&Self> for Rational {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: &Self) -> Self::Output { Self(self.0 * &rhs.0) }
|
||||
}
|
||||
|
||||
impl ops::Div<&Rational> for Rational {
|
||||
type Output = Rational;
|
||||
fn div(self, rhs: &Rational) -> Self::Output { Self(self.0 / &rhs.0) }
|
||||
impl ops::Div<&Self> for Rational {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: &Self) -> Self::Output { Self(self.0 / &rhs.0) }
|
||||
}
|
||||
|
||||
impl ops::Rem<&Rational> for Rational {
|
||||
type Output = Rational;
|
||||
fn rem(self, _rhs: &Rational) -> Self::Output {
|
||||
impl ops::Rem<&Self> for Rational {
|
||||
type Output = Self;
|
||||
fn rem(self, _rhs: &Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
@ -238,26 +225,26 @@ impl ops::RemAssign for Rational {
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::AddAssign<&Rational> for Rational {
|
||||
fn add_assign(&mut self, rhs: &Rational) { self.0 += &rhs.0 }
|
||||
impl ops::AddAssign<&Self> for Rational {
|
||||
fn add_assign(&mut self, rhs: &Self) { self.0 += &rhs.0 }
|
||||
}
|
||||
|
||||
impl ops::SubAssign<&Rational> for Rational {
|
||||
fn sub_assign(&mut self, rhs: &Rational) { self.0 -= &rhs.0 }
|
||||
impl ops::SubAssign<&Self> for Rational {
|
||||
fn sub_assign(&mut self, rhs: &Self) { self.0 -= &rhs.0 }
|
||||
}
|
||||
|
||||
impl ops::MulAssign<&Rational> for Rational {
|
||||
fn mul_assign(&mut self, rhs: &Rational) { self.0 *= &rhs.0 }
|
||||
impl ops::MulAssign<&Self> for Rational {
|
||||
fn mul_assign(&mut self, rhs: &Self) { self.0 *= &rhs.0 }
|
||||
}
|
||||
|
||||
impl ops::DivAssign<&Rational> for Rational {
|
||||
fn div_assign(&mut self, _rhs: &Rational) {
|
||||
impl ops::DivAssign<&Self> for Rational {
|
||||
fn div_assign(&mut self, _rhs: &Self) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::RemAssign<&Rational> for Rational {
|
||||
fn rem_assign(&mut self, _rhs: &Rational) {
|
||||
impl ops::RemAssign<&Self> for Rational {
|
||||
fn rem_assign(&mut self, _rhs: &Self) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
@ -267,33 +254,33 @@ impl ops::Neg for &Rational {
|
||||
fn neg(self) -> Self::Output { Rational(rug::Rational::from(-&self.0)) }
|
||||
}
|
||||
|
||||
impl ops::Add<&Rational> for &Rational {
|
||||
impl ops::Add<Self> for &Rational {
|
||||
type Output = Rational;
|
||||
fn add(self, _rhs: &Rational) -> Self::Output {
|
||||
fn add(self, _rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Sub<&Rational> for &Rational {
|
||||
impl ops::Sub<Self> for &Rational {
|
||||
type Output = Rational;
|
||||
fn sub(self, rhs: &Rational) -> Self::Output { Rational(rug::Rational::from(&self.0 - &rhs.0)) }
|
||||
fn sub(self, rhs: Self) -> Self::Output { Rational(rug::Rational::from(&self.0 - &rhs.0)) }
|
||||
}
|
||||
|
||||
impl ops::Mul<&Rational> for &Rational {
|
||||
impl ops::Mul<Self> for &Rational {
|
||||
type Output = Rational;
|
||||
fn mul(self, _rhs: &Rational) -> Self::Output {
|
||||
fn mul(self, _rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Div<&Rational> for &Rational {
|
||||
impl ops::Div<Self> for &Rational {
|
||||
type Output = Rational;
|
||||
fn div(self, rhs: &Rational) -> Self::Output { Rational(rug::Rational::from(&self.0 / &rhs.0)) }
|
||||
fn div(self, rhs: Self) -> Self::Output { Rational(rug::Rational::from(&self.0 / &rhs.0)) }
|
||||
}
|
||||
|
||||
impl ops::Rem<&Rational> for &Rational {
|
||||
impl ops::Rem<Self> for &Rational {
|
||||
type Output = Rational;
|
||||
fn rem(self, _rhs: &Rational) -> Self::Output {
|
||||
fn rem(self, _rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
use crate::election::{CandidateState, CountState, Election};
|
||||
use crate::numbers::{NativeFloat64, Number, Rational};
|
||||
use crate::numbers::{Fixed, NativeFloat64, Number, Rational};
|
||||
use crate::stv;
|
||||
|
||||
extern crate console_error_panic_hook;
|
||||
@ -24,11 +24,18 @@ extern crate console_error_panic_hook;
|
||||
use js_sys::Array;
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
|
||||
// Init
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn fixed_set_dps(dps: usize) {
|
||||
Fixed::set_dps(dps);
|
||||
}
|
||||
|
||||
// Helper macros for making functions
|
||||
|
||||
macro_rules! impl_type {
|
||||
($type:ident) => { paste::item! {
|
||||
// Exported functions
|
||||
// Counting
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[allow(non_snake_case)]
|
||||
@ -119,8 +126,9 @@ macro_rules! impl_type {
|
||||
}}
|
||||
}
|
||||
|
||||
impl_type!(Rational);
|
||||
impl_type!(Fixed);
|
||||
impl_type!(NativeFloat64);
|
||||
impl_type!(Rational);
|
||||
|
||||
// Reporting
|
||||
|
||||
@ -137,7 +145,7 @@ fn describe_count<N: Number>(filename: String, election: &Election<N>, opts: &st
|
||||
let mut result = String::from("<p>Count computed by OpenTally (revision ");
|
||||
result.push_str(crate::VERSION);
|
||||
let total_ballots = election.ballots.iter().fold(N::zero(), |acc, b| { acc + &b.orig_value });
|
||||
result.push_str(&format!(r#"). Read {} ballots from ‘{}’ for election ‘{}’. There are {} candidates for {} vacancies. Counting using options <span style="font-family: monospace;">{}</span>.</p>"#, total_ballots, filename, election.name, election.candidates.len(), election.seats, opts.describe::<N>()));
|
||||
result.push_str(&format!(r#"). Read {:.dps$} ballots from ‘{}’ for election ‘{}’. There are {} candidates for {} vacancies. Counting using options <span style="font-family: monospace;">{}</span>.</p>"#, total_ballots, filename, election.name, election.candidates.len(), election.seats, opts.describe::<N>(), dps=opts.pp_decimals));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user