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 🙏

© 2025 – Pkg Stats / Ryan Hefner

not-so-float

v2.5.0

Published

![NPM Version](https://img.shields.io/npm/v/not-so-float) ![NPM License](https://img.shields.io/npm/l/not-so-float) ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/victorpoughon/not-so-float/node.js.yml)

Readme

Not So Float

NPM Version NPM License GitHub Actions Workflow Status

Not So Float is a pure TypeScript library that implements Interval Union Arithmetic over IEEE 754 double precision floats (JS numbers).

[!TIP] Try the interval calculator for an interactive demo of interval union arithmetic.

import * as nsf from "not-so-float";

const X = nsf.union([nsf.interval(-10, -1), nsf.interval(100, 120)]);
const Y = nsf.union([nsf.interval(-10, 2)]);
const Q = nsf.div(X, Y);

console.log(`(${X.toString()}) / ${Y.toString()} = ${Q.toString()}`);
([-10, -1] U [100, 120]) / [-10, 2] = [-Infinity, -0.49999999999999994] U [0.09999999999999999, Infinity]

References:

Design goals:

  • No dependencies
  • Functional (stateless) API
  • Strong focus on simplicity and clarity of implementation
  • No signed zero convention, -0 === 0 should still be true in the context of interval bounds
  • Interval bounds are always inclusive
  • No empty interval, but empty unions
  • Support division by intervals containing zero without compromise

[!TIP] If you like this open-source project consider sponsoring me on GitHub, thank you ❤️

Installation

not-so-float build version is available on npm:

npm install not-so-float

Import the library with:

import * as nsf from "not-so-float";

Outward Rounding

The main interest of interval arithmetic is the inclusion property. Any interval operation result is always guaranteed to contain all possible results obtained from the underlying real operation. However floating point operations are inexact. So we must use outward rounding when computing interval bounds to maintain the inclusion property.

Unfortunately JS doesn't allow controling the IEEE 754 rounding mode, and rounds to the nearest representable float, like most programming languages. This is a computer science tragedy of the first order, because IEEE 754 actually specifies rounding modes that would allow clean implementations of interval arithmetic natively. Instead, we implement two functions: next() and prev() using typed arrays bit manipulation. These functions return the next and previous representable floating point value, exactly like the C function nextafter().

function next(x: number): number;
function prev(x: number): number;

By making sure every interval bound operation rounds outward, we can maintain the inclusion property even with numerical precision errors inherent to floating point.

Interval

An interval is a pair of IEEE 754 double precision numbers called the lower (lo) and upper (hi) bounds:

$$ [\text{ lo}, \text{ hi }] $$

The only restriction is that bounds must always be less or equal: $\text{lo} \leq \text{hi}$. The lower bound may be negative infinity, the upper bound may be positive infinity. This table describes the set of real numbers that an interval represents:

| lo | hi | Interval Type | Represents any $x \in \mathbb{R}$ such that | | :-------: | :-------: | :-----------: | :---------------------------------------------: | | $a$ | $b$ | Real | $a \leq x \leq$ b | | $-\infty$ | $b$ | Semi-Infinite | $x \leq b$ | | $a$ | $+\infty$ | Semi-Infinite | $a \leq x$ | | $-\infty$ | $+\infty$ | Infinite | $x \in \mathbb{R}$ |

Where $a$ and $b$ are real IEEE 754 values (not infinite).
The special case when both bounds are equal is called a degenerate interval.

To construct an interval, use the nsf.interval() function:

nsf.interval(a: number, b: number) : Interval

For example:

> I = nsf.interval(0, 6)
Interval { lo: 0, hi: 6 }

The interval class member functions:

class Interval {
    isFull(): boolean;
    isFinite(): boolean;
    isDegenerate(): boolean;
    contains(value: number): boolean;
    hull(): Union;
    superset(other: Interval): boolean;
    subset(other: Interval): boolean;
    width(): number;
    toString(numbers?: (x: number) => string): string;
    print(): void;
}

Union

A union is an ordered disjoint set of intervals:

$$ [a, b] \cup [c, d] \ldots \cup [e, f] $$

To construct a union, use the nsf.union() function:

function union(list: (Interval | Union)[]): Union

Union class member functions:

class Union {
    isEmpty(): boolean;
    isFull(): boolean;
    isFinite(): boolean;
    isSingle(): boolean;
    equalsSingle(lower: number, upper: number): boolean;
    count(): number;
    lower(): number;
    upper(): number;
    contains(value: number): boolean;
    subset(other: Union): boolean;
    superset(other: Union): boolean;
    hull(): Union;
    width(): number;
    forEach(callback: (x: Interval, index: number) => void): void;
    toString(numbers?: (x: number) => string): string;
    print(): void;
}

For example:

> const U = nsf.union([nsf.inter(1, 2), nsf.inter(4, 6)])
> U.toString()
'[1, 2] U [4, 6]'
> U.intervals
[ Interval { lo: 1, hi: 2 }, Interval { lo: 4, hi: 6 } ]

You can also use the shorthand nsf.single() to construct a singleton, i.e. a union with a single interval:

const U = nsf.single(-0.1, 0.1);

Constants are also provided:

  • FULL: all real numbers
  • EMPTY: the empty union

Set theory

Compare and compute intervals and unions with the following implementations of set theory operations:

function overlap(A: Interval | Union, B: Interval | Union): boolean;
function disjoint(A: Interval | Union, B: Interval | Union): boolean;
function intersection(A: Interval | Union, B: Interval | Union): Union;
function complement(A: Union | Interval): Union;

Arithmetic

| Operation | API function | | ------------------------------------------: | :----------------- | | Addition | nsf.add(A, B) | | Unary negation | nsf.neg(A) | | Subtraction | nsf.sub(A, B) | | Multiplication | nsf.mul(A, B) | | Division | nsf.div(A, B) | | Exponentiation(integer exponent) | nsf.powInt(A, n) | | Exponentiation(interval/union exponent) | nsf.pow(A, B) |

[!IMPORTANT] Note that every operation returns a union. This is for consistency, because while some operations (add, sub, mul) between intervals can return a single interval, others (division, exponentiation, log, sqrt) can return zero, one or two disjoint intervals even with interval inputs.

Unary Functions

| Operation | API function | | ----------------: | :------------- | | Absolute value | nsf.abs(A) | | Natural logarithm | nsf.log(A) | | Exponential | nsf.exp(A) | | Square root | nsf.sqrt(A) | | Inverse square | nsf.sqinv(A) | | Cosine | nsf.cos(A) | | Sine | nsf.sin(A) | | Tangent | nsf.tan(A) |

Binary Functions

| Operation | API function | | --------: | :-------------- | | Minimum | nsf.min(A, B) | | Maximum | nsf.max(A, B) |

Future improvements

  • Support multiple rounding modes
  • Improve unit test coverage