Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions factorion-bot-discord/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "factorion-bot-discord"
version = "3.0.3"
version = "3.0.4"
edition = "2024"
description = "factorion-bot (for factorials and related) on Discord"
license = "MIT"
Expand All @@ -10,7 +10,7 @@ keywords = ["factorial", "termial", "bot", "math", "discord"]
categories = ["mathematics", "web-programming", "parser-implementations"]

[dependencies]
factorion-lib = { path = "../factorion-lib", version = "6.0.3", features = ["serde", "influxdb"] }
factorion-lib = { path = "../factorion-lib", version = "6.0.4", features = ["serde", "influxdb"] }
serenity = { version = "0.12", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "cache"] }
tokio = { version = "1.48.0", features = ["macros", "rt-multi-thread", "time"] }
dotenvy = "^0.15.7"
Expand Down
4 changes: 2 additions & 2 deletions factorion-bot-reddit/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "factorion-bot-reddit"
version = "6.0.3"
version = "6.0.4"
edition = "2024"
description = "factorion-bot (for factorials and related) on Reddit"
license = "MIT"
Expand All @@ -10,7 +10,7 @@ keywords = ["factorial", "termial", "bot", "math"]
categories = ["mathematics", "web-programming", "parser-implementations"]

[dependencies]
factorion-lib = {path = "../factorion-lib", version = "6.0.3", features = ["serde", "influxdb"]}
factorion-lib = {path = "../factorion-lib", version = "6.0.4", features = ["serde", "influxdb"]}
reqwest = { version = "0.12.28", features = ["json", "native-tls"], default-features = false }
serde = { version = "1.0.219", default-features = false, features = ["derive"] }
serde_json = "1.0.145"
Expand Down
4 changes: 2 additions & 2 deletions factorion-lib/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "factorion-lib"
version = "6.0.3"
version = "6.0.4"
edition = "2024"
description = "A library used to create bots to recognize and calculate factorials and related concepts"
license = "MIT"
Expand All @@ -10,7 +10,7 @@ keywords = ["factorial", "termial", "bot", "math"]
categories = ["mathematics", "web-programming", "parser-implementations"]

[dependencies]
factorion-math = {path = "../factorion-math", version = "1.0.5"}
factorion-math = {path = "../factorion-math", version = "1.0.6"}
serde = {version = "1.0", features = ["derive"], optional = true}
serde_json = {version = "1.0", optional = true}
concat-idents = "1.1.4"
Expand Down
30 changes: 25 additions & 5 deletions factorion-lib/src/calculation_tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ impl CalculationJob {
) -> Option<CalculationResult> {
let prec = consts.float_precision;
let calc_num = match num {
CalculationResult::ComplexInfinity => return Some(CalculationResult::ComplexInfinity),
Number::Float(num) | CalculationResult::Approximate(num, _)
if !num.as_float().is_finite() =>
{
return Some(CalculationResult::ComplexInfinity);
}
CalculationResult::Approximate(base, exponent) => {
if exponent <= consts.integer_construction_limit {
let x: Float = base.as_float() * Float::with_val(prec, 10).pow(&exponent);
Expand Down Expand Up @@ -194,7 +200,6 @@ impl CalculationJob {
CalculationResult::ApproximateDigitsTower(false, false, depth + 1, exponent)
});
}
CalculationResult::ComplexInfinity => return Some(CalculationResult::ComplexInfinity),
Number::Float(num) => match level {
..-1 => {
// We don't support multitermials of decimals
Expand Down Expand Up @@ -233,6 +238,20 @@ impl CalculationJob {
}
}
},
Number::Exact(num) if num.significant_bits() >= math::rug::float::exp_max() as u32 => {
let sig_bits = num.significant_bits();
return Self::calculate_appropriate_factorial(
CalculationResult::Approximate(
(Float::with_val(consts.float_precision, num / consts.float_precision)
/ (sig_bits - consts.float_precision))
.into(),
sig_bits.into(),
),
level,
negative,
consts,
);
}
Number::Exact(num) => num,
};
if level > 0 {
Expand Down Expand Up @@ -332,18 +351,19 @@ impl CalculationJob {
} else if level < 0 {
Some(
if calc_num.significant_bits() > consts.upper_termial_approximation_limit {
let termial = math::approximate_termial_digits(calc_num, -level as u32, prec);
let termial =
math::approximate_termial_digits(calc_num, level.unsigned_abs(), prec);
CalculationResult::ApproximateDigits(!negative.is_multiple_of(2), termial)
} else if calc_num > consts.upper_termial_limit {
let termial = math::approximate_termial(calc_num, -level as u32, prec);
} else if *calc_num.as_abs() > consts.upper_termial_limit {
let termial = math::approximate_termial(calc_num, level.unsigned_abs(), prec);
CalculationResult::Approximate(
((termial.0 * if !negative.is_multiple_of(2) { -1 } else { 1 }) as Float)
.into(),
termial.1,
)
} else {
let termial = if level < -1 {
math::multitermial(calc_num, -level as u32)
math::multitermial(calc_num, level.unsigned_abs())
} else {
math::termial(calc_num)
};
Expand Down
29 changes: 20 additions & 9 deletions factorion-lib/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ pub mod recommended {
pub static INTEGER_CONSTRUCTION_LIMIT: fn() -> Integer = || 200_000_000u128.into();
}

// NOTE: Most of these rely on being ascii (byte indxed)

const POI_STARTS: &[char] = &[
NEGATION,
'!', // PREFIX_OPS
Expand Down Expand Up @@ -167,7 +169,7 @@ pub fn parse(
text = &text[position_of_interest..];
if text.starts_with(ESCAPE) {
// Escapes
text = &text[1..];
text = &text[ESCAPE.len_utf8()..];
let end = if text.starts_with(SPOILER_START) {
1
} else if text.starts_with(SPOILER_HTML_START) {
Expand Down Expand Up @@ -195,7 +197,10 @@ pub fn parse(
}
end += e;
// is escaped -> look further
if text[end.saturating_sub(1)..].starts_with(ESCAPE) {
let potential_escape = end.saturating_sub(ESCAPE.len_utf8());
if text.is_char_boundary(potential_escape)
&& text[end.saturating_sub(ESCAPE.len_utf8())..].starts_with(ESCAPE)
{
end += 1;
continue;
}
Expand All @@ -220,7 +225,10 @@ pub fn parse(
}
end += e;
// is escaped -> look further
if text[end.saturating_sub(1)..].starts_with(ESCAPE) {
let potential_escape = end.saturating_sub(ESCAPE.len_utf8());
if text.is_char_boundary(potential_escape)
&& text[end.saturating_sub(ESCAPE.len_utf8())..].starts_with(ESCAPE)
{
end += 1;
continue;
}
Expand Down Expand Up @@ -248,11 +256,11 @@ pub fn parse(
jobs.push(*job);
}
current_negative = 0;
text = &text[1..];
text = &text[PAREN_START.len_utf8()..];
continue;
} else if text.starts_with(PAREN_END) {
// Paren End (5.)
text = &text[1..];
text = &text[PAREN_END.len_utf8()..];
current_negative = 0;
// Paren mismatch?
let Some(step) = paren_steps.pop() else {
Expand Down Expand Up @@ -388,7 +396,7 @@ pub fn parse(
if text.starts_with(PAREN_START) {
paren_steps.push((current_negative, Some(level), false));
current_negative = 0;
text = &text[1..];
text = &text[PAREN_START.len_utf8()..];
}
continue;
};
Expand Down Expand Up @@ -708,7 +716,7 @@ fn parse_num_simple(
part
};
let decimal_part = if text.starts_with(locale.decimal) {
*text = &text[1..];
*text = &text[locale.decimal.len_utf8()..];
let end = text
.find(|c: char| (!c.is_numeric() && !SEPARATORS.contains(&c)) || c == locale.decimal)
.unwrap_or(text.len());
Expand Down Expand Up @@ -828,6 +836,9 @@ fn parse_num_simple(
} else {
Integer::ONE.clone()
};
if divisor == 0 {
return Some(Number::ComplexInfinity);
}
let integer_part = integer_part.replace(SEPARATORS, "");
let decimal_part = decimal_part.replace(SEPARATORS, "");
if exponent >= decimal_part.len() as i64
Expand Down Expand Up @@ -855,7 +866,7 @@ fn parse_num_simple(
} else if x.is_finite() {
Some(Number::Float(x.into()))
} else {
None
Some(Number::ComplexInfinity)
}
} else {
let x = Float::parse(format!("{integer_part}.{decimal_part}")).ok()?;
Expand All @@ -864,7 +875,7 @@ fn parse_num_simple(
let (b, e) = crate::math::adjust_approximate((x, exponent));
Some(Number::Approximate(b.into(), e))
} else {
None
Some(Number::ComplexInfinity)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion factorion-math/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "factorion-math"
version = "1.0.5"
version = "1.0.6"
edition = "2024"
description = "The math (factorials and related functions) used by factorion"
license = "MIT"
Expand Down
5 changes: 3 additions & 2 deletions factorion-math/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub fn factorial(n: u64, k: u32) -> Integer {
/// The k-factorial of -n is the factorial of n-k times this factor (inf if None)
pub fn negative_multifacorial_factor(n: Integer, k: i32) -> Option<Integer> {
let n = -n;
let rem = n.rem(2 * k);
let rem = n.rem(2 * (k as i64));
if rem == 0 {
None
} else if rem < k {
Expand Down Expand Up @@ -271,14 +271,15 @@ pub fn approximate_termial_float(k: u32, n: Float) -> (Float, Integer) {
let prec = n.prec();
let len: Integer = n
.clone()
.abs()
.log10()
.to_integer_round(rug::float::Round::Down)
.unwrap()
.0;
let len_10 = Float::with_val(prec, 10).pow(len.clone());
let a = n.clone() / len_10.clone();
let b = (n + k) / len_10;
adjust_approximate(((a * b) / (2 * k), 2 * len))
adjust_approximate(((a * b) / (2 * Float::with_val(prec, k)), 2 * len))
}

/// The k-termial of x * 10^e as a * 10^b
Expand Down
Loading