diff --git a/.lock b/.lock new file mode 100644 index 0000000..e69de29 diff --git a/crates.js b/crates.js new file mode 100644 index 0000000..46726f1 --- /dev/null +++ b/crates.js @@ -0,0 +1 @@ +window.ALL_CRATES = ["ratio"]; \ No newline at end of file diff --git a/help.html b/help.html new file mode 100644 index 0000000..788810e --- /dev/null +++ b/help.html @@ -0,0 +1 @@ +
The type of ratios and related operations.
+A ratio is the result of dividing two integers, i.e., the numerator and +denominator.
+use ratio::Ratio;
+
+let ratio = Ratio::new(1, 3); // 1 / 3
+assert_eq!(ratio.mul_trunc(20), 6); // trunc(20 * 1 / 3) = trunc(6.66..) = 6
+assert_eq!(ratio.mul_round(20), 7); // round(20 * 1 / 3) = round(6.66..) = 7
+println!("{:?}", ratio); // Ratio(1/3 ~= 1431655765/4294967296)
pub struct Ratio { /* private fields */ }
The ratio type.
+It converts numerator / denominator
to mult / (1 << shift)
to avoid
+u128
division on calculation. The shift
is as large as possible to
+improve precision.
Currently, it only supports u32
as the numerator and denominator.
Creates a new ratio numerator / denominator
.
Get the inverse ratio.
+use ratio::Ratio;
+
+let ratio = Ratio::new(1, 2);
+assert_eq!(ratio.inverse(), Ratio::new(2, 1));
Multiplies the ratio by a value and rounds the result down.
+use ratio::Ratio;
+
+let ratio = Ratio::new(2, 3);
+assert_eq!(ratio.mul_trunc(99), 66); // 99 * 2 / 3 = 66
+assert_eq!(ratio.mul_trunc(100), 66); // trunc(100 * 2 / 3) = trunc(66.66...) = 66
Multiplies the ratio by a value and rounds the result to the nearest +whole number.
+use ratio::Ratio;
+
+let ratio = Ratio::new(2, 3);
+assert_eq!(ratio.mul_round(99), 66); // 99 * 2 / 3 = 66
+assert_eq!(ratio.mul_round(100), 67); // round(100 * 2 / 3) = round(66.66...) = 67
U::from(self)
.\nGet the inverse ratio.\nMultiplies the ratio by a value and rounds the result to …\nMultiplies the ratio by a value and rounds the result down.\nCreates a new ratio numerator / denominator
.\nThe zero ratio.")
\ No newline at end of file
diff --git a/settings.html b/settings.html
new file mode 100644
index 0000000..756e3c4
--- /dev/null
+++ b/settings.html
@@ -0,0 +1 @@
+1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +
//! The type of ratios and related operations.
+//!
+//! A **ratio** is the result of dividing two integers, i.e., the numerator and
+//! denominator.
+//!
+//! # Examples
+//!
+//! ```
+//! use ratio::Ratio;
+//!
+//! let ratio = Ratio::new(1, 3); // 1 / 3
+//! assert_eq!(ratio.mul_trunc(20), 6); // trunc(20 * 1 / 3) = trunc(6.66..) = 6
+//! assert_eq!(ratio.mul_round(20), 7); // round(20 * 1 / 3) = round(6.66..) = 7
+//! println!("{:?}", ratio); // Ratio(1/3 ~= 1431655765/4294967296)
+//! ```
+
+#![cfg_attr(not(test), no_std)]
+
+use core::{cmp::PartialEq, fmt};
+
+/// The ratio type.
+///
+/// It converts `numerator / denominator` to `mult / (1 << shift)` to avoid
+/// `u128` division on calculation. The `shift` is as large as possible to
+/// improve precision.
+///
+/// Currently, it only supports `u32` as the numerator and denominator.
+pub struct Ratio {
+ numerator: u32,
+ denominator: u32,
+ mult: u32,
+ shift: u32,
+}
+
+impl Ratio {
+ /// The zero ratio.
+ pub const fn zero() -> Self {
+ Self {
+ numerator: 0,
+ denominator: 0,
+ mult: 0,
+ shift: 0,
+ }
+ }
+
+ /// Creates a new ratio `numerator / denominator`.
+ pub const fn new(numerator: u32, denominator: u32) -> Self {
+ assert!(!(denominator == 0 && numerator != 0));
+ if numerator == 0 {
+ return Self {
+ numerator,
+ denominator,
+ mult: 0,
+ shift: 0,
+ };
+ }
+
+ // numerator / denominator == (numerator * (1 << shift) / denominator) / (1 << shift)
+ let mut shift = 32;
+ let mut mult;
+ loop {
+ mult = (((numerator as u64) << shift) + denominator as u64 / 2) / denominator as u64;
+ if mult <= u32::MAX as u64 || shift == 0 {
+ break;
+ }
+ shift -= 1;
+ }
+
+ while mult % 2 == 0 && shift > 0 {
+ mult /= 2;
+ shift -= 1;
+ }
+
+ Self {
+ numerator,
+ denominator,
+ mult: mult as u32,
+ shift,
+ }
+ }
+
+ /// Get the inverse ratio.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use ratio::Ratio;
+ ///
+ /// let ratio = Ratio::new(1, 2);
+ /// assert_eq!(ratio.inverse(), Ratio::new(2, 1));
+ /// ```
+ pub const fn inverse(&self) -> Self {
+ Self::new(self.denominator, self.numerator)
+ }
+
+ /// Multiplies the ratio by a value and rounds the result down.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use ratio::Ratio;
+ ///
+ /// let ratio = Ratio::new(2, 3);
+ /// assert_eq!(ratio.mul_trunc(99), 66); // 99 * 2 / 3 = 66
+ /// assert_eq!(ratio.mul_trunc(100), 66); // trunc(100 * 2 / 3) = trunc(66.66...) = 66
+ /// ```
+ pub const fn mul_trunc(&self, value: u64) -> u64 {
+ ((value as u128 * self.mult as u128) >> self.shift) as u64
+ }
+
+ /// Multiplies the ratio by a value and rounds the result to the nearest
+ /// whole number.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use ratio::Ratio;
+ ///
+ /// let ratio = Ratio::new(2, 3);
+ /// assert_eq!(ratio.mul_round(99), 66); // 99 * 2 / 3 = 66
+ /// assert_eq!(ratio.mul_round(100), 67); // round(100 * 2 / 3) = round(66.66...) = 67
+ /// ```
+ pub const fn mul_round(&self, value: u64) -> u64 {
+ ((value as u128 * self.mult as u128 + (1 << self.shift >> 1)) >> self.shift) as u64
+ }
+}
+
+impl fmt::Debug for Ratio {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(
+ f,
+ "Ratio({}/{} ~= {}/{})",
+ self.numerator,
+ self.denominator,
+ self.mult,
+ 1u64 << self.shift
+ )
+ }
+}
+
+impl PartialEq<Ratio> for Ratio {
+ #[inline]
+ fn eq(&self, other: &Ratio) -> bool {
+ self.mult == other.mult && self.shift == other.shift
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_ratio() {
+ let a = Ratio::new(625_000, 1_000_000);
+ let b = Ratio::new(1, u32::MAX);
+ let c = Ratio::new(u32::MAX, u32::MAX);
+ let d = Ratio::new(u32::MAX, 1);
+
+ assert_eq!(a.mult, 5);
+ assert_eq!(a.shift, 3);
+ assert_eq!(a.mul_trunc(800), 500);
+
+ assert_eq!(b.mult, 1);
+ assert_eq!(b.shift, 32);
+ assert_eq!(b.mul_trunc(u32::MAX as _), 0);
+ assert_eq!(b.mul_round(u32::MAX as _), 1);
+
+ assert_eq!(c.mult, 1);
+ assert_eq!(c.shift, 0);
+ assert_eq!(c.mul_trunc(u32::MAX as _), u32::MAX as _);
+
+ println!("{:?}", a);
+ println!("{:?}", b);
+ println!("{:?}", c);
+ println!("{:?}", d);
+ }
+
+ #[test]
+ fn test_zero() {
+ let z1 = Ratio::new(0, 100);
+ let z2 = Ratio::zero();
+ let z3 = Ratio::new(0, 0);
+ assert_eq!(z1.mul_trunc(233), 0);
+ assert_eq!(z2.mul_trunc(0), 0);
+ assert_eq!(z3.mul_round(456), 0);
+ }
+}
+
fn:
) to \
+ restrict the search to a given item kind.","Accepted kinds are: fn
, mod
, struct
, \
+ enum
, trait
, type
, macro
, \
+ and const
.","Search functions by type signature (e.g., vec -> usize
or \
+ -> vec
or String, enum:Cow -> bool
)","You can look for items with an exact name by putting double quotes around \
+ your request: \"string\"
","Look for functions that accept or return \
+ slices and \
+ arrays by writing \
+ square brackets (e.g., -> [u8]
or [] -> Option
)","Look for items inside another one by searching for a path: vec::Vec
",].map(x=>""+x+"
").join("");const div_infos=document.createElement("div");addClass(div_infos,"infos");div_infos.innerHTML="${value.replaceAll(" ", " ")}
`}else{error[index]=value}});output+=`