Skip to content

Commit d64b58b

Browse files
committed
range: Check zero-divide in ranges
When dividing by a range that contains zero, emit a range with infinities. Signed-off-by: Christophe de Dinechin <[email protected]>
1 parent 8005ff0 commit d64b58b

File tree

2 files changed

+29
-11
lines changed

2 files changed

+29
-11
lines changed

src/range.cc

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -346,10 +346,14 @@ range_g operator*(range_r x, range_r y)
346346
{
347347
if (!x|| !y)
348348
return nullptr;
349-
algebraic_g a = x->lo() * y->lo();
350-
algebraic_g b = x->lo() * y->hi();
351-
algebraic_g c = x->hi() * y->lo();
352-
algebraic_g d = x->hi() * y->hi();
349+
algebraic_g xlo = x->lo();
350+
algebraic_g xhi = x->hi();
351+
algebraic_g ylo = y->lo();
352+
algebraic_g yhi = y->hi();
353+
algebraic_g a = xlo * ylo;
354+
algebraic_g b = xlo * yhi;
355+
algebraic_g c = xhi * ylo;
356+
algebraic_g d = xhi * yhi;
353357

354358
range::sort(a, b);
355359
range::sort(a, c);
@@ -367,10 +371,21 @@ range_g operator/(range_r x, range_r y)
367371
{
368372
if (!x|| !y)
369373
return nullptr;
370-
algebraic_g a = x->lo() / y->lo();
371-
algebraic_g b = x->lo() / y->hi();
372-
algebraic_g c = x->hi() / y->lo();
373-
algebraic_g d = x->hi() / y->hi();
374+
algebraic_g xlo = x->lo();
375+
algebraic_g xhi = x->hi();
376+
algebraic_g ylo = y->lo();
377+
algebraic_g yhi = y->hi();
378+
if (ylo->is_zero(false) || yhi->is_zero(false) ||
379+
ylo->is_negative(false) != yhi->is_negative())
380+
{
381+
ylo = rt.infinity(true);
382+
yhi = rt.infinity(false);
383+
return range::make(y->type(), ylo, yhi);
384+
}
385+
algebraic_g a = xlo / ylo;
386+
algebraic_g b = xlo / yhi;
387+
algebraic_g c = xhi / ylo;
388+
algebraic_g d = xhi / yhi;
374389

375390
range::sort(a, b);
376391
range::sort(a, c);

src/tests.cc

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5389,11 +5389,13 @@ void tests::range_types()
53895389
step("Multiply delta ranges")
53905390
.test(CLEAR, "1±3 2±5", NOSHIFT, MUL).expect("7±21");
53915391
step("Divide delta ranges")
5392-
.test(CLEAR, "1±3 2±5", NOSHIFT, DIV).expect("-¹/₃±1");
5392+
.test(CLEAR, "10±3 20±5", NOSHIFT, DIV).expect("⁴³/₇₅±²²/₇₅")
5393+
.test(CLEAR, "1±3 2±5", NOSHIFT, DIV).expect("−∞…∞");
53935394
step("Power delta ranges")
53945395
.test(CLEAR, "2±1 5±2", NOSHIFT, ID_pow).expect("1 094.±1 093.");
53955396
step("Invert delta ranges")
5396-
.test(CLEAR, "1±3", NOSHIFT, ID_inv).expect("-¹/₈±³/₈");
5397+
.test(CLEAR, "10±3", NOSHIFT, ID_inv).expect("¹⁰/₉₁±³/₉₁")
5398+
.test(CLEAR, "1±3", NOSHIFT, ID_inv).expect("−∞…∞");
53975399
step("Negate delta ranges")
53985400
.test(CLEAR, "1±3", ENTER, ID_neg).expect("-1±3");
53995401

@@ -5415,7 +5417,8 @@ void tests::range_types()
54155417
step("Multiply delta ranges")
54165418
.test(CLEAR, "5 1±3", NOSHIFT, MUL).expect("5±15");
54175419
step("Divide delta ranges")
5418-
.test(CLEAR, "5 1±3", NOSHIFT, DIV).expect("-⁵/₈±1 ⁷/₈");
5420+
.test(CLEAR, "5 10±3", NOSHIFT, DIV).expect("⁵⁰/₉₁±¹⁵/₉₁")
5421+
.test(CLEAR, "5 1±3", NOSHIFT, DIV).expect("−∞…∞");
54195422
step("Power delta ranges")
54205423
.test(CLEAR, "5 1±3", NOSHIFT, ID_pow).expect("312.52±312.48");
54215424

0 commit comments

Comments
 (0)