npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

o-quantity

v3.1.0

Published

A library for quantity arithmetic and units

Downloads

5

Readme

Quantity

A library for quantity arithmetic and units

Quantities

A Quantity is an amount of some unit that handles comparisons and basic arithmetic operations.

Documentation

http://o-programming-language.org/

Why use Quantity objects?

A Quantity object uses the knowledge of its own unit to convert and compare itself with other equivalent units.

Than means that the only points in the application where the program must be aware of units and apply transformations are when it reads the quantity from a source like an API, database or user interface and when it writes the quantity to a target like an API, datatabase or user interface.

During the rest of the execution the program deals transparently with variables regardless of their actual units.

Also Quantity objects validate that arithmetic operations are evaluated with other equivalent units and will raise an error when a non equivalent unit is used flagging the units missmatch immediatly instead of silently producing a wrong value.

Arithmetic

Create quantity of a metric unit and do arithmetic operations with it

const {Kg, Gr, Mg, Lt} = require('o-quantity')

const quantity1 = Kg.amount(1)
const quantity2 = Gr.amount(250)

const total = quantity1.op('+', quantity2)

Units are properly converted if required.

Comparison

const limit = Kg.amount(3)
if( total.is('>', limit ) {
  // ...
}

If units are not comparable the comparison will throw a NonEquivalentUnitsComparisonError:

Kg.amount(1).is('>', Lt.amount(1))

Convertions

Standard units can be expressed in other units of the same metric system

const {Kg} = require('o-quantity')

const quantity = Kg.amount(1)

quantity.toKg()
quantity.toGr()
quantity.toMg()
quantity.toLbs()
quantity.toOz()

While these convertions are not required for comparisons and arithmetic operations they can be used to show Quantities to users, to store quantities in a database and to communicate with external APIs.

Standard units

At this moment the standard units implemented in o-quantity are

// Quantity of weight

const {
  Kg,
  Hg,
  Dag,
  Gr,
  Dg,
  Cg,
  Mg,
  Oz,
  Lbs
} = require('o-quantity')

// Quantity of volume
const {
  Kl,
  Hl,
  Dal,
  Lt,
  Dl,
  Cl,
  Ml
} = require('o-quantity')

// Quantity of distance
const {
  Km,
  Hm,
  Dam,
  Mt,
  Dm,
  Cm,
  Mm
} = require('o-quantity')

// Quantity of storage

const {
  Gb,
  Mb,
  Kb,
  Bt
} = require('o-quantity')

// Quantity of time
const {
  Weeks,
  Days,
  Hours,
  Minutes,
  Seconds,
  Milliseconds
} = require('o-quantity')

Non standard units

A Quantity object has two components, an amount and a unit.

Usually the amount is a scalar value like a float or an integer or a value object like a RationalNumber or a FixedPointNumber.

The unit can also be any object, not just standard metric system units.

For example

const {Quantity} = require('o-quantity')

const quantity1 = new Quantity(1, 'points')
const quantity2 = new Quantity(2, 'points')

const total = quantity1.op('+', quantity2)

The same rules apply as for standard units.

For example the comparison below will throw a NonEquivalentUnitsComparisonError:

const {Quantity, Kg} = require('o-quantity')

const quantity1 = new Quantity(1, 'points')
quantity1.is('==', Kg.amount(1))

Precision

To compare quantities with a given precision use ~= and ~== (read it like 'approximately equal to').

Operator ~== raises an error if the comparison is with a not equivalente unit. For example

Kg.amount(1.01).is('~==', Lt.amount(1.0099)) // error

Operator ~= returns false if the comparison is with a not equivalente unit. For example

Kg.amount(1.01).is('~=', Lt.amount(1.0099)) // false

ArithmeticObjects

The following classes are ArithmeticObjects:

  • FloatNumber
  • FixedPointNumber
  • RationalNumber
  • Quantity

While each class implementation is different and has its own specifics they all implement the following protocol:

const n
const m

const result = n.op('+', m)
const result = n.op('-', m)
const result = n.op('*', m)
const result = n.op('/', m)

const result = n.is('==', m)
const result = n.is('===', m)
const result = n.is('~=', m)
const result = n.is('~==', m)
const result = n.is('>', m)
const result = n.is('>=', m)
const result = n.is('<', m)
const result = n.is('<=', m)

n.toNumber()

or if you prefer the method version

const n
const m

const result = n.plus(m)
const result = n.minus(m)
const result = n.multiplyBy(m)
const result = n.divideBy(m)

const result = n.equals(m)
const result = n.comparedTo(m)
const result = n.equalsWithPrecision(m, 0.01)
const result = n.comparedToWithPrecision(m, 0,001)
const result = n.greaterThan(m)
const result = n.greaterOrEqualThan(m)
const result = n.lowerThan(m)
const result = n.lowerOrEqualThan(m)

n.toNumber()

FloatNumber

FloatNumber are wrappers of javascript built-in Integer and Double numbers.

The reason to wrap them is to have a polymorphic procotol with other implementations of numbers like FixedPointNumber and be able to do things like

const result = n.plus(m)
const result = n.equals(m)

regardless of whether n and m are built-in values or complex objects.

FixedPointNumber

A FixedPointNumber is a number with a fixed number of decimal places. For example

1.02

is a FixedPointNumber with 2 decimal places.

The difference with floating point numbers is the precision used in its arithmetic operations. FixedPointNumbers will round to its number of decimal places on every operation. That makes it a good fit for handling amounts of money where the precision is 2 decimal places.

The comparison and arithmetic operations with FixedPointNumbers are the same as with Quantities:

const n = new FixedPointNumber(1.01, { decimals: 2 })
const m = new FixedPointNumber(1.02, { decimals: 2 })

const result = n.op('+', m)

except that arithmetic operations might take an additional optional parameter to get the remainder of the operation:

const n = new FixedPointNumber(10.00, { decimals: 2 })

const tail = {}
const result = n.op('/', 3, tail)

tail.tail === 0.00333
tail.rounded === 0

to allow each use case to decide what to do with the rounding remainder of the operation.

RationalNumber

A RationalNumber is a number treated like a pair of (numerator / denominator) integers instead of a floating point number.

All operations are done with numerators and denominators using Integer arithmetic therefore avoiding the accumulation of rounding errors.

A RationalNumber can be created from any other number

const n = new RationalNumber(10)
const n = new RationalNumber(0.5)
const n = new RationalNumber({ numerator: 1, denominator: 2 })
const n = new RationalNumber(new FloatNumber(0.5))
const n = new RationalNumber(new FixedPointNumber(0.5, { decimals: 2 }))

and the comparisons and operations are the same as for any ArithmeticObject.

Convertion between number types

To convert FloatNumber, RationalNumber or FixedPointNumber to a regular float, for example to communicate the value to an external API or database, use

n.toNumber()

To convert between number types use

n.toFloatNumber()
n.toRationalNumber()
n.toFixedPointNumber()

Musical Scales

Important

Before using this implementation of Musical Scales please we aware that this is an experimental work in progress and, more important, that I am a fairly recent student of music, not a music expert, and this work is part of my musical study resources and practical works.

Meaning that it would be safer (and wiser) to validate all of these concepts with your own teachers of music while using it.

ChromaticNote

A ChromaticNote is an abstract chromatic note. Abstract means that is not in a concrete position in a scale but rather in reference to its sorrounding ChromaticNotes.

The available ChromaticNotes are

const {
  Do_b, Do, Do_d,
  Re_b, Re, Re_d,
  Mi_b, Mi, Mi_d,
  Fa_b, Fa, Fa_d,
  Sol_b, Sol, Sol_d,
  La_b, La, La_d,
  Si_b, Si, Si_d
} = require('o-quantity').MusicalScale

and can be dynamically queried with

const { MusicalScale } = require('o-quantity')

const allNamedNotes = MusicalScale.ChromaticNote.getAllNotes()

_b stands for the note accidental bemol and _d for note accidental diesis.

A ChromaticNote supports the following operations:

const note = Si

note.isBemol()
note.isDiesis()
note.getNoteName() // returns the name of the note without its accidentals
note.getSymbolName()
note.getName()
note.getWithoutAccidentals() // the same note without its accidentals
note.getNextNote() // the following note in the cromatic scale preserving accidentals 
note.getNextSemitone() // the following note at a half tone distance
note.at(height) // a ScaleNote at the given height, Height 0 is the piano middle Do
note.equals(otherNote)
note.is('==', otherNote)
note.is('>', otherNote)
note.is('>=', otherNote)
note.is('<', otherNote)
note.is('<=', otherNote)

A ScaleNote is a ChromaticNote note in a position in the scale. The position is relative to the piano middle Do, which has a position (or height) of 0.

To create a ScaleNote define a position in a ChromaticNote:

Do.at(0)
La_d.at(-1)
Fa.at(3)

ScaleNote supports the same operations as a ChromaticNote plus:

Do.at(0).getHeight()
Do.at(0).up(Major3.amount(1))
La_d.at(-1).up(Perfect5.amount(3))
Fa.at(3).down(Semitones.amount(6))
Do.at(0).staffDisplayString() // a textual staff print in major G key
Do.at(0).displayString()

The available interval distances are:

Semitone,
Tone,
Minor2,
Major2,
Minor3,
Major3,
Perfect4,
Augmented4,
Perfect5,
Minor6,
Major6,
Minor7,
Major7,
Perfect8

and can be dynamically queried with

const { MusicalScale } = require('o-quantity')

const allNamedDistances = MusicalScale.ChromaticScaleDistance.getAllDistances()