From f964816830a3cd59e9c6b236556ce0ef85a215cd Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Thu, 8 Oct 2026 12:19:36 +0200 Subject: [PATCH] Refuse a rows weight too close to 0 to tell from it, by the rule a JSON option uses --- internal/grammar/calc.go | 8 ++++++++ internal/rows/rows.go | 8 ++++++-- node.go | 7 ++----- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/internal/grammar/calc.go b/internal/grammar/calc.go index 8ecca45..341936b 100644 --- a/internal/grammar/calc.go +++ b/internal/grammar/calc.go @@ -4,6 +4,7 @@ import ( "fmt" "slices" "strconv" + "strings" "unicode" ) @@ -177,3 +178,10 @@ func (p *calcParser) ident() (CalcNode, error) { } return CalcVar{name, at}, nil } + +// Underflows reports a number written as text that reads as f = 0 though a digit before its +// exponent is not 0, as 1e-400 does: no float64 holds the number written. +func Underflows(text string, f float64) bool { + mantissa, _, _ := strings.Cut(strings.ToLower(text), "e") + return f == 0 && strings.ContainsAny(mantissa, "123456789") +} diff --git a/internal/rows/rows.go b/internal/rows/rows.go index 23a7bdf..aa00b73 100644 --- a/internal/rows/rows.go +++ b/internal/rows/rows.go @@ -218,9 +218,13 @@ func (t *Table[O]) sumWeights() error { t.weights, t.cum = make([]float64, t.Len()), make([]float64, t.Len()) total := 0.0 for r := range t.cum { - w, err := strconv.ParseFloat(t.Cell(r, t.weightIndex), 64) + cell := t.Cell(r, t.weightIndex) + w, err := strconv.ParseFloat(cell, 64) if err != nil || math.IsInf(w, 0) || math.IsNaN(w) || w < 0 { - return fmt.Errorf("%s line %d: weight %q is not a number of 0 or more", t.file, r+2, t.Cell(r, t.weightIndex)) + return fmt.Errorf("%s line %d: weight %q is not a number of 0 or more", t.file, r+2, cell) + } + if grammar.Underflows(cell, w) { + return fmt.Errorf("%s line %d: weight %s is too close to 0 to tell from it", t.file, r+2, cell) } total += w t.weights[r], t.cum[r] = w, total diff --git a/node.go b/node.go index adc8cd4..09efe82 100644 --- a/node.go +++ b/node.go @@ -5,7 +5,6 @@ import ( "fmt" "math" "strconv" - "strings" "github.com/larvit/fejkdata/internal/datafiles" "github.com/larvit/fejkdata/internal/grammar" @@ -385,11 +384,9 @@ func weightOf(raw any) (float64, error) { return w, notTiny("weight", wv, w) } -// notTiny refuses the number v of option name where it reads as 0 though a digit of it is not -// 0, as 1e-400 does: no float64 holds the number written. +// notTiny refuses the number v of option name where grammar.Underflows does. func notTiny(name string, v any, f float64) error { - mantissa, _, _ := strings.Cut(strings.ToLower(string(v.(json.Number))), "e") - if f == 0 && strings.ContainsAny(mantissa, "123456789") { + if grammar.Underflows(string(v.(json.Number)), f) { return fmt.Errorf("%s %s is too close to 0 to tell from it", name, v) } return nil