Skip to content

Commit 7806754

Browse files
committed
make calculations more consistent
parse small "digits"s and "tower"s as integer calculate more exact termial of "digits" do not write 1 × in truncate do not return rough as true in truncate when only zeroes were cut only turn "approx" and "digits" into integers when below integer_contruction_limit
1 parent 474f8a7 commit 7806754

8 files changed

Lines changed: 135 additions & 46 deletions

File tree

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

factorion-bot-discord/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "factorion-bot-discord"
3-
version = "2.4.0"
3+
version = "2.4.1"
44
edition = "2024"
55
description = "factorion-bot (for factorials and related) on Discord"
66
license = "MIT"
@@ -10,7 +10,7 @@ keywords = ["factorial", "termial", "bot", "math", "discord"]
1010
categories = ["mathematics", "web-programming", "parser-implementations"]
1111

1212
[dependencies]
13-
factorion-lib = { path = "../factorion-lib", version = "4.4.0", features = ["serde", "influxdb"] }
13+
factorion-lib = { path = "../factorion-lib", version = "4.4.1", features = ["serde", "influxdb"] }
1414
serenity = { version = "0.12", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "cache"] }
1515
tokio = { version = "1.48.0", features = ["macros", "rt-multi-thread", "time"] }
1616
dotenvy = "^0.15.7"

factorion-bot-reddit/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "factorion-bot-reddit"
3-
version = "5.5.0"
3+
version = "5.5.1"
44
edition = "2024"
55
description = "factorion-bot (for factorials and related) on Reddit"
66
license = "MIT"
@@ -10,7 +10,7 @@ keywords = ["factorial", "termial", "bot", "math"]
1010
categories = ["mathematics", "web-programming", "parser-implementations"]
1111

1212
[dependencies]
13-
factorion-lib = {path = "../factorion-lib", version = "4.4.0", features = ["serde", "influxdb"]}
13+
factorion-lib = {path = "../factorion-lib", version = "4.4.1", features = ["serde", "influxdb"]}
1414
reqwest = { version = "0.12.28", features = ["json", "native-tls"], default-features = false }
1515
serde = { version = "1.0.219", default-features = false, features = ["derive"] }
1616
serde_json = "1.0.140"

factorion-lib/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "factorion-lib"
3-
version = "4.4.0"
3+
version = "4.4.1"
44
edition = "2024"
55
description = "A library used to create bots to recognize and calculate factorials and related concepts"
66
license = "MIT"

factorion-lib/src/calculation_results.rs

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! This module handles the formatting of the calculations (`The factorial of Subfactorial of 5 is`, etc.)
22
3+
use factorion_math::rug::Complete;
4+
use factorion_math::rug::integer::IntegerExt64;
35
#[cfg(any(feature = "serde", test))]
46
use serde::{Deserialize, Serialize};
57

@@ -583,11 +585,16 @@ fn truncate(number: &Integer, consts: &Consts) -> (String, bool) {
583585
.to_integer_round(crate::rug::float::Round::Down)
584586
.unwrap()
585587
.0;
586-
let truncated_number: Integer = &number
587-
/ (Float::with_val(prec, 10)
588-
.pow((length.clone() - consts.number_decimals_scientific - 1u8).max(Integer::ZERO))
589-
.to_integer()
590-
.unwrap());
588+
let ten_exp = Integer::u64_pow_u64(
589+
10,
590+
(length.clone() - consts.number_decimals_scientific - 1u8)
591+
.max(Integer::ZERO)
592+
.to_u64()
593+
.unwrap(),
594+
)
595+
.complete();
596+
let rough = !number.is_divisible(&ten_exp);
597+
let truncated_number: Integer = &number / ten_exp;
591598
let mut truncated_number = truncated_number.to_string();
592599
if truncated_number.len() > consts.number_decimals_scientific {
593600
round(&mut truncated_number);
@@ -609,7 +616,11 @@ fn truncate(number: &Integer, consts: &Consts) -> (String, bool) {
609616
truncated_number.insert(0, '-');
610617
}
611618
if length > consts.number_decimals_scientific + 1 {
612-
(format!("{truncated_number} × 10^{length}"), true)
619+
if truncated_number == "1" {
620+
(format!("10^{length}"), rough)
621+
} else {
622+
(format!("{truncated_number} × 10^{length}"), rough)
623+
}
613624
} else {
614625
(orig_number.to_string(), false)
615626
}
@@ -806,23 +817,39 @@ mod tests {
806817
&consts
807818
)
808819
.0,
809-
"1 × 10^300"
820+
"10^300"
821+
);
822+
assert_eq!(
823+
truncate(
824+
&Integer::from_str(&format!("1{}", "0".repeat(300))).unwrap(),
825+
&consts
826+
)
827+
.1,
828+
false
829+
);
830+
assert_eq!(
831+
truncate(
832+
&Integer::from_str(&format!("2{}", "0".repeat(300))).unwrap(),
833+
&consts
834+
)
835+
.0,
836+
"2 × 10^300"
810837
);
811838
assert_eq!(
812839
truncate(
813-
&-Integer::from_str(&format!("1{}", "0".repeat(300))).unwrap(),
840+
&-Integer::from_str(&format!("2{}", "0".repeat(300))).unwrap(),
814841
&consts
815842
)
816843
.0,
817-
"-1 × 10^300"
844+
"-2 × 10^300"
818845
);
819846
assert_eq!(
820847
truncate(
821-
&Integer::from_str(&format!("1{}", "0".repeat(2000000))).unwrap(),
848+
&Integer::from_str(&format!("2{}", "0".repeat(2000000))).unwrap(),
822849
&consts
823850
)
824851
.0,
825-
"1 × 10^2000000"
852+
"2 × 10^2000000"
826853
);
827854
}
828855

factorion-lib/src/calculation_tasks.rs

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,9 @@ impl CalculationJob {
132132
let prec = consts.float_precision;
133133
let calc_num = match num {
134134
CalculationResult::Approximate(base, exponent) => {
135-
let res = base.as_float() * Float::with_val(prec, 10).pow(&exponent);
136-
if Float::is_finite(&(res.clone() * math::APPROX_FACT_SAFE_UPPER_BOUND_FACTOR)) {
137-
res.to_integer().unwrap()
135+
if exponent <= consts.integer_construction_limit {
136+
let x: Float = base.as_float() * Float::with_val(prec, 10).pow(&exponent);
137+
x.to_integer().unwrap()
138138
} else {
139139
return Some(if base.as_float() < &0.0 {
140140
CalculationResult::ComplexInfinity
@@ -143,7 +143,11 @@ impl CalculationJob {
143143
(Float::from(base), exponent),
144144
-level as u32,
145145
);
146-
CalculationResult::Approximate(termial.0.into(), termial.1)
146+
if termial.0 == 1 {
147+
CalculationResult::ApproximateDigits(false, termial.1)
148+
} else {
149+
CalculationResult::Approximate(termial.0.into(), termial.1)
150+
}
147151
} else {
148152
let mut exponent = exponent;
149153
exponent.add_from(math::length(&exponent, prec));
@@ -152,17 +156,32 @@ impl CalculationJob {
152156
}
153157
}
154158
CalculationResult::ApproximateDigits(was_neg, digits) => {
155-
return Some(if digits.is_negative() {
156-
CalculationResult::Float(Float::new(prec).into())
157-
} else if was_neg {
158-
CalculationResult::ComplexInfinity
159-
} else if level < 0 {
160-
CalculationResult::ApproximateDigits(false, (digits - 1) * 2 + 1)
159+
if digits <= consts.integer_construction_limit {
160+
let x: Float = Float::with_val(prec, 10).pow(digits.clone() - 1);
161+
x.to_integer().unwrap()
161162
} else {
162-
let mut digits = digits;
163-
digits.add_from(math::length(&digits, prec));
164-
CalculationResult::ApproximateDigitsTower(false, false, 1.into(), digits)
165-
});
163+
return Some(if digits.is_negative() {
164+
CalculationResult::Float(Float::new(prec).into())
165+
} else if was_neg {
166+
CalculationResult::ComplexInfinity
167+
} else if level < 0 {
168+
let mut one = Float::with_val(consts.float_precision, 1);
169+
if was_neg {
170+
one *= -1;
171+
}
172+
let termial =
173+
math::approximate_approx_termial((one, digits), -level as u32);
174+
if termial.0 == 1 {
175+
CalculationResult::ApproximateDigits(false, termial.1)
176+
} else {
177+
CalculationResult::Approximate(termial.0.into(), termial.1)
178+
}
179+
} else {
180+
let mut digits = digits;
181+
digits.add_from(math::length(&digits, prec));
182+
CalculationResult::ApproximateDigitsTower(false, false, 1.into(), digits)
183+
});
184+
}
166185
}
167186
CalculationResult::ApproximateDigitsTower(was_neg, neg, depth, exponent) => {
168187
return Some(if neg {

factorion-lib/src/parse.rs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::{
1212
pub mod recommended {
1313
use factorion_math::rug::Integer;
1414

15-
pub static INTEGER_CONSTRUCTION_LIMIT: fn() -> Integer = || 10_000_000u128.into();
15+
pub static INTEGER_CONSTRUCTION_LIMIT: fn() -> Integer = || 200_000_000u128.into();
1616
}
1717

1818
const POI_STARTS: &[char] = &[
@@ -579,12 +579,19 @@ fn parse_num(
579579
*text = &text[3..];
580580
let part = part.replace(SEPARATORS, "");
581581
let n = part.parse::<Integer>().ok()?;
582-
return Some(Number::ApproximateDigitsTower(
583-
false,
584-
false,
585-
n - 1,
586-
1.into(),
587-
));
582+
match n.to_usize() {
583+
Some(0) => return Some(1.into()),
584+
Some(1) => return Some(10.into()),
585+
Some(2) => return Some(Number::Exact(10_000_000_000u64.into())),
586+
_ => {
587+
return Some(Number::ApproximateDigitsTower(
588+
false,
589+
false,
590+
n - 1,
591+
1.into(),
592+
));
593+
}
594+
}
588595
} else {
589596
// Skip ^ only (because ret None)
590597
*text = orig_text;
@@ -666,6 +673,11 @@ fn parse_num(
666673
}
667674

668675
if depth == 1 {
676+
if top < consts.integer_construction_limit {
677+
return Some(Number::Exact(
678+
Integer::u64_pow_u64(10, top.to_u64().unwrap()).complete(),
679+
));
680+
}
669681
return Some(Number::ApproximateDigits(false, top));
670682
} else {
671683
return Some(Number::ApproximateDigitsTower(
@@ -1846,6 +1858,17 @@ mod test {
18461858
5.into()
18471859
))
18481860
);
1861+
let num = parse_num(
1862+
&mut "10^50000000000",
1863+
false,
1864+
false,
1865+
&consts,
1866+
&NumFormat::V1(&locale::v1::NumFormat { decimal: '.' }),
1867+
);
1868+
assert_eq!(
1869+
num,
1870+
Some(Number::ApproximateDigits(false, 50000000000u64.into()))
1871+
);
18491872
let num = parse_num(
18501873
&mut "10^5!",
18511874
false,
@@ -1861,7 +1884,7 @@ mod test {
18611884
&consts,
18621885
&NumFormat::V1(&locale::v1::NumFormat { decimal: '.' }),
18631886
);
1864-
assert_eq!(num, Some(Number::ApproximateDigits(false, 5.into())));
1887+
assert_eq!(num, Some(Number::Exact(100000.into())));
18651888
let num = parse_num(
18661889
&mut "10^5",
18671890
false,

0 commit comments

Comments
 (0)