Skip to content

Commit e8bac1f

Browse files
committed
Fix unit_of-related problems
Introduces some alternative helpers to `unit_of`
1 parent 587f720 commit e8bac1f

File tree

11 files changed

+168
-39
lines changed

11 files changed

+168
-39
lines changed

book/src/list-functions-math.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -886,24 +886,24 @@ Compute the numerical derivative of the function \\( f \\) at point \\( x \\) us
886886
More information [here](https://en.wikipedia.org/wiki/Numerical_differentiation).
887887

888888
```nbt
889-
fn diff<X: Dim, Y: Dim>(f: Fn[(X) -> Y], x: X) -> Y / X
889+
fn diff<X: Dim, Y: Dim>(f: Fn[(X) -> Y], x: X, Δx: X) -> Y / X
890890
```
891891

892892
<details>
893893
<summary>Examples</summary>
894894

895895
Compute the derivative of \\( f(x) = x² -x -1 \\) at \\( x=1 \\).
896-
<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code" onclick=" window.open('https://numbat.dev/?q=use%20numerics%3A%3Adiff%0Afn%20polynomial%28x%29%20%3D%20x%C2%B2%20%2D%20x%20%2D%201%0Adiff%28polynomial%2C%201%29')""></button></div><code class="language-nbt hljs numbat">use numerics::diff
896+
<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code" onclick=" window.open('https://numbat.dev/?q=use%20numerics%3A%3Adiff%0Afn%20polynomial%28x%29%20%3D%20x%C2%B2%20%2D%20x%20%2D%201%0Adiff%28polynomial%2C%201%2C%201e%2D10%29')""></button></div><code class="language-nbt hljs numbat">use numerics::diff
897897
fn polynomial(x) = x² - x - 1
898-
diff(polynomial, 1)
898+
diff(polynomial, 1, 1e-10)
899899

900900
= 1.0
901901
</code></pre>
902902

903903
Compute the free fall velocity after \\( t=2 s \\).
904-
<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code" onclick=" window.open('https://numbat.dev/?q=use%20numerics%3A%3Adiff%0Afn%20distance%28t%29%20%3D%200%2E5%20g0%20t%C2%B2%0Afn%20velocity%28t%29%20%3D%20diff%28distance%2C%20t%29%0Avelocity%282%20s%29')""></button></div><code class="language-nbt hljs numbat">use numerics::diff
904+
<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code" onclick=" window.open('https://numbat.dev/?q=use%20numerics%3A%3Adiff%0Afn%20distance%28t%29%20%3D%200%2E5%20g0%20t%C2%B2%0Afn%20velocity%28t%29%20%3D%20diff%28distance%2C%20t%2C%201e%2D10%20s%29%0Avelocity%282%20s%29')""></button></div><code class="language-nbt hljs numbat">use numerics::diff
905905
fn distance(t) = 0.5 g0 t²
906-
fn velocity(t) = diff(distance, t)
906+
fn velocity(t) = diff(distance, t, 1e-10 s)
907907
velocity(2 s)
908908

909909
= 19.6133 m/s [Velocity]

book/src/list-functions-other.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,77 @@ fn unit_of<T: Dim>(x: T) -> T
189189

190190
</details>
191191

192+
### `has_unit`
193+
Returns true if `quantity` has the same unit as `unit_query`, or if `quantity` evaluates to zero.
194+
195+
```nbt
196+
fn has_unit<T: Dim>(quantity: T, unit_query: T) -> Bool
197+
```
198+
199+
<details>
200+
<summary>Examples</summary>
201+
202+
<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code" onclick=" window.open('https://numbat.dev/?q=has%5Funit%2820%20km%2Fh%2C%20km%2Fh%29')""></button></div><code class="language-nbt hljs numbat">has_unit(20 km/h, km/h)
203+
204+
= true [Bool]
205+
</code></pre>
206+
207+
<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code" onclick=" window.open('https://numbat.dev/?q=has%5Funit%2820%20km%2Fh%2C%20m%2Fs%29')""></button></div><code class="language-nbt hljs numbat">has_unit(20 km/h, m/s)
208+
209+
= false [Bool]
210+
</code></pre>
211+
212+
</details>
213+
214+
### `is_dimensionless`
215+
Returns true if `quantity` is dimensionless, or if `quantity` is zero.
216+
217+
```nbt
218+
fn is_dimensionless<T: Dim>(quantity: T) -> Bool
219+
```
220+
221+
<details>
222+
<summary>Examples</summary>
223+
224+
<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code" onclick=" window.open('https://numbat.dev/?q=is%5Fdimensionless%2810%29')""></button></div><code class="language-nbt hljs numbat">is_dimensionless(10)
225+
226+
= true [Bool]
227+
</code></pre>
228+
229+
<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code" onclick=" window.open('https://numbat.dev/?q=is%5Fdimensionless%2810%20km%2Fh%29')""></button></div><code class="language-nbt hljs numbat">is_dimensionless(10 km/h)
230+
231+
= false [Bool]
232+
</code></pre>
233+
234+
</details>
235+
236+
### `unit_name`
237+
Returns a string representation of the unit of `quantity`. Returns an empty string if `quantity` is dimensionless.
238+
239+
```nbt
240+
fn unit_name<T: Dim>(quantity: T) -> String
241+
```
242+
243+
<details>
244+
<summary>Examples</summary>
245+
246+
<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code" onclick=" window.open('https://numbat.dev/?q=unit%5Fname%2820%29')""></button></div><code class="language-nbt hljs numbat">unit_name(20)
247+
248+
= "" [String]
249+
</code></pre>
250+
251+
<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code" onclick=" window.open('https://numbat.dev/?q=unit%5Fname%2820%20m%5E2%29')""></button></div><code class="language-nbt hljs numbat">unit_name(20 m^2)
252+
253+
= "m²" [String]
254+
</code></pre>
255+
256+
<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code" onclick=" window.open('https://numbat.dev/?q=unit%5Fname%2820%20km%2Fh%29')""></button></div><code class="language-nbt hljs numbat">unit_name(20 km/h)
257+
258+
= "km/h" [String]
259+
</code></pre>
260+
261+
</details>
262+
192263
## Chemical elements
193264

194265
Defined in: `chemistry::elements`

examples/tests/core.nbt

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
# value_of
2+
3+
assert_eq(value_of(0), 0)
4+
5+
assert_eq(value_of(1), 1)
6+
assert_eq(value_of(1.2345), 1.2345)
7+
8+
assert_eq(value_of(1 m), 1)
9+
assert_eq(value_of(1.2345 m), 1.2345)
10+
11+
assert_eq(value_of(1 m^2/s), 1)
12+
assert_eq(value_of(1.2345 m^2/s), 1.2345)
13+
114
# unit_of
215

316
assert_eq(unit_of(1), 1)
@@ -9,18 +22,32 @@ assert_eq(unit_of(1.2345 m), m)
922
assert_eq(unit_of(1 m^2/s), m^2/s)
1023
assert_eq(unit_of(1.2345 m^2/s), m^2/s)
1124

12-
# value_of
25+
# has_unit
1326

14-
assert_eq(value_of(0), 0)
27+
assert(has_unit(1 m, m))
28+
assert(has_unit(2 m, m))
1529

16-
assert_eq(value_of(1), 1)
17-
assert_eq(value_of(1.2345), 1.2345)
30+
assert(!has_unit(1 m, cm))
31+
assert(!has_unit(1 m, km))
32+
assert(!has_unit(1 m, ft))
1833

19-
assert_eq(value_of(1 m), 1)
20-
assert_eq(value_of(1.2345 m), 1.2345)
34+
assert(has_unit(0, m))
35+
assert(has_unit(0, cm))
36+
assert(has_unit(0, s))
2137

22-
assert_eq(value_of(1 m^2/s), 1)
23-
assert_eq(value_of(1.2345 m^2/s), 1.2345)
38+
# is_dimensionless
39+
40+
assert(is_dimensionless(0))
41+
assert(is_dimensionless(1))
42+
assert(!is_dimensionless(1 m))
43+
assert(!is_dimensionless(1 m/s))
44+
45+
# unit_name
46+
47+
assert_eq(unit_name(0), "")
48+
assert_eq(unit_name(1), "")
49+
assert_eq(unit_name(1 m), "m")
50+
assert_eq(unit_name(1 m^2/s), "m²/s")
2451

2552
# round, round_in
2653

examples/tests/numerics.nbt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,17 @@ assert_eq(fixed_point(f_sqrt3, 1, 1e-10), sqrt(3), 1e-10)
1919

2020
# Differentiation
2121

22-
assert_eq(diff(log, 2.0), 0.5, 1e-5)
22+
assert_eq(diff(log, 2.0, 1e-10), 0.5, 1e-5)
2323

24-
# TODO: Sadly, the following is not possible at the moment. See https://github.com/sharkdp/numbat/issues/521 for details
25-
# assert_eq(diff(sin, 0.0), 1.0, 1e-5)
24+
assert_eq(diff(sin, 0.0, 1e-10), 1.0, 1e-5)
2625

27-
assert_eq(diff(sqrt, 1.0), 0.5, 1e-5)
26+
assert_eq(diff(sqrt, 1.0, 1e-10), 0.5, 1e-5)
2827

2928
fn f2(x: Scalar) -> Scalar = x² + 4 x + 1
3029

31-
assert_eq(diff(f2, 2.0), 8.0, 1e-5)
30+
assert_eq(diff(f2, 2.0, 1e-10), 8.0, 1e-5)
3231

3332
fn dist(t: Time) -> Length = 0.5 g0 t^2
34-
fn velocity(t: Time) -> Velocity = diff(dist, t)
33+
fn velocity(t: Time) -> Velocity = diff(dist, t, 1e-10 s)
3534

3635
assert_eq(velocity(2.0 s), 2.0 s × g0, 1e-3 m/s)

numbat/modules/core/quantities.nbt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,19 @@ fn value_of<T: Dim>(x: T) -> Scalar
99
@example("unit_of(20 km/h)")
1010
fn unit_of<T: Dim>(x: T) -> T = if x_value == 0 then error("Invalid argument: cannot call `unit_of` on a value that evaluates to 0") else x / value_of(x)
1111
where x_value = value_of(x)
12+
13+
@description("Returns true if `quantity` has the same unit as `unit_query`, or if `quantity` evaluates to zero.")
14+
@example("has_unit(20 km/h, km/h)")
15+
@example("has_unit(20 km/h, m/s)")
16+
fn has_unit<T: Dim>(quantity: T, unit_query: T) -> Bool
17+
18+
@description("Returns true if `quantity` is dimensionless, or if `quantity` is zero.")
19+
@example("is_dimensionless(10)")
20+
@example("is_dimensionless(10 km/h)")
21+
fn is_dimensionless<T: Dim>(quantity: T) -> Bool
22+
23+
@description("Returns a string representation of the unit of `quantity`. Returns an empty string if `quantity` is dimensionless.")
24+
@example("unit_name(20)")
25+
@example("unit_name(20 m^2)")
26+
@example("unit_name(20 km/h)")
27+
fn unit_name<T: Dim>(quantity: T) -> String

numbat/modules/datetime/functions.nbt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,18 +62,18 @@ fn _add_years(dt: DateTime, n_years: Scalar) -> DateTime
6262
@description("Adds the given time span to a `DateTime`. This uses leap-year and DST-aware calendar arithmetic with variable-length days, months, and years.")
6363
@example("calendar_add(datetime(\"2022-07-20 21:52 +0200\"), 2 years)")
6464
fn calendar_add(dt: DateTime, span: Time) -> DateTime =
65-
if span_unit == days
65+
if span == 0
66+
then dt
67+
else if has_unit(span, days)
6668
then _add_days(dt, span / days)
67-
else if span_unit == months
69+
else if has_unit(span, months)
6870
then _add_months(dt, span / months)
69-
else if span_unit == years
71+
else if has_unit(span, years)
7072
then _add_years(dt, span / years)
71-
else if span_unit == seconds || span_unit == minutes || span_unit == hours
73+
else if has_unit(span, seconds) || has_unit(span, minutes) || has_unit(span, hours)
7274
then dt + span
7375
else
74-
error("calendar_add: Unsupported unit: {span_unit}")
75-
where
76-
span_unit = unit_of(span)
76+
error("calendar_add: Unsupported unit for `span`")
7777

7878
@description("Subtract the given time span from a `DateTime`. This uses leap-year and DST-aware calendar arithmetic with variable-length days, months, and years.")
7979
@example("calendar_sub(datetime(\"2022-07-20 21:52 +0200\"), 3 years)")

numbat/modules/numerics/diff.nbt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ use core::quantities
33
@name("Numerical differentiation")
44
@url("https://en.wikipedia.org/wiki/Numerical_differentiation")
55
@description("Compute the numerical derivative of the function $f$ at point $x$ using the central difference method.")
6-
@example("fn polynomial(x) = x² - x - 1\ndiff(polynomial, 1)", "Compute the derivative of $f(x) = x² -x -1$ at $x=1$.")
7-
@example("fn distance(t) = 0.5 g0 t²\nfn velocity(t) = diff(distance, t)\nvelocity(2 s)", "Compute the free fall velocity after $t=2 s$.")
8-
fn diff<X: Dim, Y: Dim>(f: Fn[(X) -> Y], x: X) -> Y / X =
6+
@example("fn polynomial(x) = x² - x - 1\ndiff(polynomial, 1, 1e-10)", "Compute the derivative of $f(x) = x² -x -1$ at $x=1$.")
7+
@example("fn distance(t) = 0.5 g0 t²\nfn velocity(t) = diff(distance, t, 1e-10 s)\nvelocity(2 s)", "Compute the free fall velocity after $t=2 s$.")
8+
fn diff<X: Dim, Y: Dim>(f: Fn[(X) -> Y], x: X, Δx: X) -> Y / X =
99
(f(x + Δx) - f(x - Δx)) / 2 Δx
10-
where
11-
Δx = 1e-10 × unit_of(x)

numbat/modules/plot/bar_chart.nbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ fn _default_label(n: Scalar) -> String = "{n}"
1515
fn bar_chart<A: Dim>(values: List<A>) -> BarChart =
1616
BarChart {
1717
value_label: "",
18-
value_unit: if _is_scalar(head(values)) then "" else _unit_name(head(values)),
18+
value_unit: unit_name(head(values)),
1919
values: map(value_of, values),
2020
x_labels: map(_default_label, range(1, len(values))),
2121
}

numbat/modules/plot/common.nbt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
use core::quantities
22
use core::strings
33

4-
fn _unit_name<A: Dim>(x: A) -> String = str_replace("1 ", "", "{unit_of(x)}")
5-
6-
fn _is_scalar<A: Dim>(x: A) -> Bool = "{unit_of(x)}" == "1"
7-
84
# TODO: this function is overly generic, but we don't have bounded
95
# polymorphism yet.
106
fn show<Plot>(plot: Plot) -> String

numbat/modules/plot/line_plot.nbt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ let _num_points_for_line_plot = 2000
1515
fn line_plot<A: Dim, B: Dim>(f: Fn[(A) -> B], x_start: A, x_end: A) -> LinePlot =
1616
LinePlot {
1717
x_label: "",
18-
x_unit: if _is_scalar(x_end) then "" else _unit_name(x_end),
18+
x_unit: unit_name(x_end),
1919
y_label: "",
20-
y_unit: if _is_scalar(f(x_end)) then "" else _unit_name(f(x_end)),
21-
xs: linspace(x_start / unit_of(x_start), x_end / unit_of(x_end), _num_points_for_line_plot),
20+
y_unit: unit_name(f(x_end)),
21+
xs: linspace(value_of(x_start), value_of(x_end), _num_points_for_line_plot),
2222
ys: map(value_of, map(f, linspace(x_start, x_end, _num_points_for_line_plot))),
2323
}
2424

0 commit comments

Comments
 (0)