| Crates.io | reduction-factor |
| lib.rs | reduction-factor |
| version | 0.1.0 |
| created_at | 2025-08-25 08:58:22.240614+00 |
| updated_at | 2025-08-25 08:58:22.240614+00 |
| description | Provides a type representing reduction factor. |
| homepage | |
| repository | https://github.com/Mainzu/reduction-factor |
| max_upload_size | |
| id | 1809243 |
| size | 17,976 |
A tiny, #![no_std]-compatible crate for representing and correctly composing reduction factors, like discounts or damage resistance.
A Reduction<T> is a newtype wrapper around a value x of type T that semantically represents a multiplicative factor of 1 - x.
This is useful for modeling concepts like:
Reduction(0.25), which applies a multiplier of 0.75.Reduction(0.10), which means you take 0.90 times the damage.Reduction(0.10), which represents a success rate of 0.90.The main benefit of this wrapper type is ensuring that multiple reductions are composed (or "stacked") correctly.
*) to stack reductions or apply them to values, making your code clear and intuitive.f32, f64, or custom fixed-point types for applications requiring perfect precision).Reduction<T> has the same memory layout and performance as the underlying type T.no_std compatible: Usable in embedded, WASM, and other resource-constrained environments.Create a Reduction and apply it to a value using the * operator or the reduce method.
use reduction_factor::Reduction;
let discount = Reduction::new(0.25f32); // A 25% reduction
let price = 100.0;
// This calculates `price * (1.0 - 0.25)`
let final_price = discount * price;
assert_eq!(final_price, 75.0);
// You can also use the `reduce` method for clarity
assert_eq!(discount.reduce(price), 75.0);
This is the core feature of the crate. When you multiply two Reductions, they are composed mathematically correctly.
The composition logic is derived from the multiplicative nature of reductions. Applying a reduction x followed by a reduction y is equivalent to multiplying by (1 - x) and then by (1 - y). The combined multiplier is (1 - x) * (1 - y), which simplifies to 1 - (x + y - xy). The Reduction type handles this calculation automatically when you use the multiplication operator.
For a concrete example of combining 20% and 10% reductions on a value of 100:
100 * (1 - 0.20) = 8080 * (1 - 0.10) = 72100 - 72 = 28, which is a 28% reduction, not 30%.The Reduction type makes this effortless:
use reduction_factor::Reduction;
let armor_resistance = Reduction(0.20); // 20%
let magic_shield = Reduction(0.10); // 10%
// Combine the two reductions using multiplication
let total_resistance = armor_resistance * magic_shield;
// The combined reduction is 0.28, or 28%
assert_eq!(*total_resistance, 0.28);
let incoming_damage = 100.0;
let damage_taken = total_resistance * incoming_damage;
assert_eq!(damage_taken, 72.0);
The multiplication operator (*) is used for this composition because the operation is commutative (order doesn't matter) and associative (grouping doesn't matter), just like standard multiplication.
Reduction::none(): A 0% reduction (Reduction(0)). This is the multiplicative identity for composition. Any reduction composed with none() remains unchanged. It is also the Default.Reduction::full(): A 100% reduction (Reduction(1)). This is the absorbing element (or annihilator). Any reduction composed with full() becomes a full() reduction.use reduction_factor::Reduction;
// Identity element
let no_change = Reduction::none(); // 0%
let r = Reduction(0.25);
assert_eq!(r * no_change, r);
// Absorbing element
let full_reduction = Reduction::full(); // 100%
// Note: Floating point precision may affect exact equality checks.
assert_eq!(r * full_reduction, full_reduction);
assert_eq!(full_reduction * 50.0, 0.0);