mirror of
https://git.pumpin.online/funkpower/catena.git
synced 2026-10-22 18:57:14 +00:00
bibclean: slugs, and whether the one a record has still names it
This commit is contained in:
@@ -15,6 +15,6 @@ pub mod pattern;
|
||||
pub mod segment;
|
||||
pub mod tokens;
|
||||
|
||||
pub use number::decimal;
|
||||
pub use number::{decimal, percent, round_half_to_even};
|
||||
pub use segment::{is_space, paragraphs, sentences};
|
||||
pub use tokens::{count, decode_lossy, encode, split_at_token_limit};
|
||||
|
||||
@@ -47,6 +47,28 @@ fn digit_value(c: char) -> Option<u32> {
|
||||
ten.then_some(value)
|
||||
}
|
||||
|
||||
/// Round half to even, which is what Python's `round` does and what Rust's
|
||||
/// does not: `round(2.5)` is 2 there and 3 here.
|
||||
///
|
||||
/// It matters wherever a rounded number decides something — how many
|
||||
/// chapters a recording gets, what a percentage in a report reads as — and
|
||||
/// the two rules disagree exactly on the values that land on a boundary,
|
||||
/// which is where a disagreement is most likely to be noticed.
|
||||
pub fn round_half_to_even(value: f64) -> f64 {
|
||||
let rounded = value.round();
|
||||
if (value - value.trunc()).abs() == 0.5 && rounded % 2.0 != 0.0 {
|
||||
rounded - value.signum()
|
||||
} else {
|
||||
rounded
|
||||
}
|
||||
}
|
||||
|
||||
/// A fraction as a whole-number percentage, rounded the same way Python
|
||||
/// rounds it.
|
||||
pub fn percent(fraction: f64) -> String {
|
||||
format!("{}%", round_half_to_even(fraction * 100.0))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -84,6 +106,25 @@ mod tests {
|
||||
assert_eq!(decimal("page"), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rounding_goes_to_even_on_a_half() {
|
||||
assert_eq!(round_half_to_even(0.5), 0.0);
|
||||
assert_eq!(round_half_to_even(1.5), 2.0);
|
||||
assert_eq!(round_half_to_even(2.5), 2.0);
|
||||
assert_eq!(round_half_to_even(-2.5), -2.0);
|
||||
assert_eq!(round_half_to_even(2.4), 2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_percentage_reads_as_a_whole_number() {
|
||||
assert_eq!(percent(0.0), "0%");
|
||||
// Not 33: a third of a percent is a hair above the halfway point
|
||||
// once it is a binary float, so it rounds up rather than to even.
|
||||
assert_eq!(percent(0.335), "34%");
|
||||
assert_eq!(percent(1.0), "100%");
|
||||
assert_eq!(percent(0.125), "12%");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_absurd_number_saturates_rather_than_wrapping() {
|
||||
assert_eq!(decimal(&"9".repeat(40)), u32::MAX);
|
||||
|
||||
Reference in New Issue
Block a user