Crates.io | cpc |
lib.rs | cpc |
version | 3.0.0 |
created_at | 2020-08-20 08:52:03.002072+00 |
updated_at | 2025-08-24 02:39:48.71984+00 |
description | evaluates math expressions, with support for units and conversion between units |
homepage | https://github.com/probablykasper/cpc#readme |
repository | https://github.com/probablykasper/cpc |
max_upload_size | |
id | 278544 |
size | 465,097 |
calculation + conversion
cpc parses and evaluates strings of math, with support for units and conversion. 128-bit decimal floating points are used for high accuracy.
It also lets you mix units, so for example 1 km - 1m
results in 999 Meter
.
Try it out at cpc.kasper.space
Install using cargo
:
cargo install cpc
To install it manually, grab the appropriate binary from the GitHub Releases page and place it wherever you normally place binaries on your OS.
cpc '2h/3 to min'
3 + 4 * 2
8 % 3
(4 + 1)km to light years
10m/2s * 5 trillion s
1 lightyear * 0.001mm in km2
1m/s + 1mi/h in kilometers per h
round(sqrt(2)^4)! liters
10% of abs(sin(pi)) horsepower to watts
Add cpc
as a dependency in Cargo.toml
.
use cpc::eval;
use cpc::units::Unit;
match eval("3m + 1cm", true, Unit::Celsius, false) {
Ok(answer) => {
// answer: Number { value: 301, unit: Unit::Centimeter }
println!("Evaluated value: {} {:?}", answer.value, answer.unit)
},
Err(e) => {
println!("{e}")
}
}
cpc uses 128-bit Decimal Floating Point (d128) numbers instead of Binary Coded Decimals for better accuracy. The result cpc gives will still not always be 100% accurate. I would recommend rounding the result to 20 decimals or less.
Install Rust.
Run cpc with a CLI argument as input:
cargo run -- '100ms to s'
Run in verbose mode, which shows some extra logs:
cargo run -- '100ms to s' --verbose
Run tests:
cargo test
Build:
cargo build
Nice resources for adding units:
In src/units.rs
, units are specified like this:
pub enum UnitType {
Time,
// etc
}
// ...
create_units!(
Nanosecond: (Time, d128!(1)),
Microsecond: (Time, d128!(1000)),
// etc
)
The number associated with a unit is it's "weight". For example, if a second's weight is 1
, then a minute's weight is 60
.
Make sure to also add a test for each unit. The tests look like this:
assert_eq!(convert_test(1000.0, Meter, Kilometer), 1.0);
Basically, 1000 Meter == 1 Kilometer.
Text is turned into tokens (some of which are units) in lexer.rs
. Here's one example:
// ...
match string {
"h" | "hr" | "hrs" | "hour" | "hours" => tokens.push(Token::Unit(Hour)),
// etc
}
// ...
CHANGELOG.md
Cargo.toml
cargo test
v#.#.#
cargo publish