[READ-ONLY] Mirror of https://github.com/kasper9n/cpc. Text calculator with support for units and conversion cpc.kasper.space
calculator cli conversion converter library math package units units-converter wasm website
Rust 96%
TypeScript 2%
Svelte 2%
HTML <1%
JavaScript <1%
CSS <1%

README.md

cpc #

calculation + conversion

cpc calculates complex strings of math, with support for units and conversion. 128-bit decimal floating points are used for high accuracy.

For example 1tonne * 1sqm / 2second^3 / 5ampere results in 100 volts.

Crates.io Documentation

List of all supported units

Web Interface #

Try it out at cpc.kasper.space

CLI Installation #

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.

CLI Usage #

cpc '2h/3 to min'

CLI REPL Usage #

cpc
> sin(1)
≈ 0.84147098480789650665250232163029899962

Examples #

3 + 4 * 2

6'3" to cm

1tonne * 1sqm / 2s^3 / 5a

(7 % 4)km to light years

10m/2s * 5 trillion s

1 lightyear * 0.001mm in km2

1m/s + 1mi/5h in kilometers per h

round(sqrt(2)^4)! liters

10% of abs(sin(pi)) horsepower to watts

Supported unit types #

  • Normal numbers
  • Angle
  • Area
  • Currency
  • Data transfer rate
  • Digital storage (bytes etc)
  • Electric current
  • Energy
  • FLOPS
  • Force
  • Frequency
  • Length
  • Mass
  • Power
  • Pressure
  • Resistance
  • Speed
  • Temperature
  • Time
  • Voltage
  • Volume

API Installation #

Add cpc as a dependency in Cargo.toml.

API Usage #

use cpc::eval;
use cpc::units::Unit;

match eval("3m + 1cm", true, false) {
    Ok(answer) => {
        // answer: Number { value: 301, unit: Unit::Centimeter }
        println!("Evaluated value: {} {:?}", answer.value, answer.unit)
    },
    Err(e) => {
        println!("{e}")
    }
}

Accuracy #

Inexact results are always indicated with ≈. 128-bit Decimal Floating Point (d128) numbers are used for high accuracy, and prevents most floating-point errors.

Dev Instructions #

Get started #

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

Adding a unit #

Nice resources for adding units:

1. Add the unit #

In src/units.rs, units are specified like this:

pub enum UnitType {
  Time,
  // etc
}

// ...

create_units!(
  Nanosecond:         (Time, d!(1), "nanosecond", "nanoseconds"),
  Microsecond:        (Time, d!(1000), "microsecond", "microseconds"),
  // 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.

2. Add a test for the unit #

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.

3. Add the unit to the lexer #

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
}
// ...

Potential Improvements #

  • Fractional numbers (to make 1/3*2*3 accurate)
  • E notation, like 2E+10
  • Unit types
    • Timezones
    • Binary/octal/decimal/hexadecimal/base32/base64
    • Color codes
    • Roman numerals

Releasing a new version #

  1. Update CHANGELOG.md
  2. Bump the version number in Cargo.toml
  3. Run cargo test
  4. Create a git tag in format v#.#.#
  5. Add release notes to the generated GitHub release and publish it
  6. Run cargo publish