Refuse an option too close to 0 to tell from it, pick a template's field position by a switch, and drop Weighted's unreachable fallback
This commit is contained in:
@@ -26,10 +26,8 @@ func (s *State) Float64() float64 { return s.rand.Float64() }
|
|||||||
func (s *State) Weighted(cum []float64) int {
|
func (s *State) Weighted(cum []float64) int {
|
||||||
total := cum[len(cum)-1]
|
total := cum[len(cum)-1]
|
||||||
x := s.Float64() * total
|
x := s.Float64() * total
|
||||||
if i := sort.Search(len(cum), func(i int) bool { return cum[i] > x }); i < len(cum) {
|
// x stays below total: a product of a float64 under 1 and a positive float64 rounds below it.
|
||||||
return i
|
return sort.Search(len(cum), func(i int) bool { return cum[i] > x })
|
||||||
}
|
|
||||||
return sort.Search(len(cum), func(i int) bool { return cum[i] >= total }) // x rounded up to the total
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seq advances the counter {seq(key)} reads, or {seq()} for an empty key, and returns it.
|
// Seq advances the counter {seq(key)} reads, or {seq()} for an empty key, and returns it.
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/larvit/fejkdata/internal/datafiles"
|
"github.com/larvit/fejkdata/internal/datafiles"
|
||||||
"github.com/larvit/fejkdata/internal/grammar"
|
"github.com/larvit/fejkdata/internal/grammar"
|
||||||
@@ -273,7 +274,12 @@ func compileTemplate(m map[string]any, pos position) (node, error) {
|
|||||||
}
|
}
|
||||||
fieldPos := inFormat
|
fieldPos := inFormat
|
||||||
if o.repeat == 1 {
|
if o.repeat == 1 {
|
||||||
fieldPos = map[position]position{atTop: inColumn, atGoTop: inGoColumn}[pos]
|
switch pos {
|
||||||
|
case atTop:
|
||||||
|
fieldPos = inColumn
|
||||||
|
case atGoTop:
|
||||||
|
fieldPos = inGoColumn
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fields, err := compileFields(m, fieldPos)
|
fields, err := compileFields(m, fieldPos)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -346,6 +352,9 @@ func repeatOf(m map[string]any) (int, error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return 0, fmt.Errorf("repeat must be a number, not %s", jsonKind(rv))
|
return 0, fmt.Errorf("repeat must be a number, not %s", jsonKind(rv))
|
||||||
}
|
}
|
||||||
|
if err := notTiny("repeat", rv, r); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
if math.IsNaN(r) || math.IsInf(r, 0) || r < 0 || r != math.Trunc(r) {
|
if math.IsNaN(r) || math.IsInf(r, 0) || r < 0 || r != math.Trunc(r) {
|
||||||
return 0, fmt.Errorf("repeat must be an integer of 0 or more, got %v", rv)
|
return 0, fmt.Errorf("repeat must be an integer of 0 or more, got %v", rv)
|
||||||
}
|
}
|
||||||
@@ -373,7 +382,17 @@ func weightOf(raw any) (float64, error) {
|
|||||||
if w < 0 || math.IsInf(w, 0) {
|
if w < 0 || math.IsInf(w, 0) {
|
||||||
return 0, fmt.Errorf("weight must be a finite number of 0 or more, got %v", wv)
|
return 0, fmt.Errorf("weight must be a finite number of 0 or more, got %v", wv)
|
||||||
}
|
}
|
||||||
return w, nil
|
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.
|
||||||
|
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") {
|
||||||
|
return fmt.Errorf("%s %s is too close to 0 to tell from it", name, v)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// numberOf reads a JSON number, one too large for a float64 as an infinity.
|
// numberOf reads a JSON number, one too large for a float64 as an infinity.
|
||||||
|
|||||||
Reference in New Issue
Block a user