Skip to content

Commit

Permalink
feat: Q string parser can handle plusMinus values
Browse files Browse the repository at this point in the history
  • Loading branch information
bradenmacdonald committed Mar 9, 2024
1 parent f41e7be commit 2837aa9
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 5 deletions.
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ x.getSI(); // { magnitude: 5, units: "kg/F" }
## Syntactic Sugar

If you prefer, there is a much more compact way to initialize `Quantity` instances: using the `Q` template helper. This
is slightly less efficient and less capable, but far more readable and convenient in many cases.
is slightly less efficient, but far more readable and convenient in many cases.

```ts
import { Q } from "@bradenmacdonald/quantity-math-js";
Expand All @@ -91,6 +91,12 @@ force.getSI(); // { magnitude: 34.2, units: "N" }
force.multiply(Q`2 s^2`).toString(); // "68.4 kg⋅m"
```

You can also call it as a function, which acts like "parse quantity string":

```ts
const force = Q("34.2 kg m/s^2"); // new Quantity(34.2, {units: "kg m/s^2"})
```

## Error/uncertainty/tolerance

You can specify a "plus/minus" value (in the same units). Operations like addition and multiplication will preserve the
Expand All @@ -99,7 +105,7 @@ relative uncertainty, etc.).

```ts
const x = new Quantity(4.52, { units: "cm", plusMinus: 0.02 }); // 4.52±0.02 cm
const y = new Quantity(2.0, { units: "cm", plusMinus: 0.2 }); // 2±0.2 cm"
const y = Q`2±0.2 cm`; // Or use the Q string syntax
const z = x.multiply(y); // z = xy = 9.04 ± 0.944 cm²
z.get(); // { magnitude: 9.04, units: "cm^2", plusMinus: 0.944 }
z.toString(); // "9.0±0.9 cm^2" (toString() will automatically round the output)
Expand Down
8 changes: 5 additions & 3 deletions q.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ export function Q(strings: string | ReadonlyArray<string>, ...keys: unknown[]):
fullString += strings[i + 1];
}
}
const match = /([-+]?\d*\.?\d*)\s*(.*)/.exec(fullString);
const match = /([-+]?\d*\.?\d*)(\s*±\s*([\d\.]+))?\s*(.*)/.exec(fullString);
if (match === null) throw new QuantityError(`Unable to parse Q template string: ${fullString}`);
const magnitude = parseFloat(match[1]);
const units = match[2];
return new Quantity(magnitude, { units });
const plusMinusStr = match[3];
const plusMinus = plusMinusStr ? parseFloat(plusMinusStr) : undefined;
const units = match[4];
return new Quantity(magnitude, { units, plusMinus });
}
8 changes: 8 additions & 0 deletions quantity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,14 @@ export class Quantity {
*
* Uses the plusMinus tolerance of this quantity value, or if no tolerance
* is set, it defaults to a relative tolerance of a hundredth of a percent.
*
* ```ts
* Q`60±5 W`.equalsApprox(Q`63 W`) // true
* Q`60±0.05 W`.equalsApprox(Q`60.1 W`) // false
* // Default tolerance of 0.01% when no ± plusMinus tolerance is specified:
* Q`100 W`.equalsApprox(Q`100.009 W`) // true
* Q`100 W`.equalsApprox(Q`100.02 W`) // false
* ```
*/
public equalsApprox(other: Quantity): boolean {
if (!this.sameDimensionsAs(other)) return false;
Expand Down
5 changes: 5 additions & 0 deletions tests/q.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,9 @@ Deno.test("Constructing Quantity instances with Q`...` template", async (t) => {
) {
await check(short, new Quantity(-.05123, { units: "kg⋅m/s^2" }));
}

await check(`15.5 ± 0.2 kg`, new Quantity(15.5, { units: "kg", plusMinus: 0.2 }));
await check(`0.2±.01 g`, new Quantity(0.2, { units: "g", plusMinus: 0.01 }));
await check(`60±5 W`, new Quantity(60, { units: "W", plusMinus: 5 }));
await check(`+60±5.0000 W`, new Quantity(60, { units: "W", plusMinus: 5 }));
});

0 comments on commit 2837aa9

Please sign in to comment.