Skip to content

Commit 0a9f320

Browse files
authored
Merge pull request #116 from alicebob/big
use 128 bit floats internally
2 parents 95e8f45 + cd51018 commit 0a9f320

File tree

5 files changed

+52
-23
lines changed

5 files changed

+52
-23
lines changed

cmd_hash.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
package miniredis
44

55
import (
6+
"math/big"
67
"strconv"
78
"strings"
89

@@ -498,7 +499,7 @@ func (m *Miniredis) cmdHincrbyfloat(c *server.Peer, cmd string, args []string) {
498499

499500
key, field, deltas := args[0], args[1], args[2]
500501

501-
delta, err := strconv.ParseFloat(deltas, 64)
502+
delta, _, err := big.ParseFloat(deltas, 10, 128, 0)
502503
if err != nil {
503504
setDirty(c)
504505
c.WriteError(msgInvalidFloat)
@@ -518,7 +519,7 @@ func (m *Miniredis) cmdHincrbyfloat(c *server.Peer, cmd string, args []string) {
518519
c.WriteError(err.Error())
519520
return
520521
}
521-
c.WriteBulk(formatFloat(v))
522+
c.WriteBulk(formatBig(v))
522523
})
523524
}
524525

cmd_string.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
package miniredis
44

55
import (
6+
"math/big"
67
"strconv"
78
"strings"
89
"time"
@@ -504,7 +505,7 @@ func (m *Miniredis) cmdIncrbyfloat(c *server.Peer, cmd string, args []string) {
504505
}
505506

506507
key := args[0]
507-
delta, err := strconv.ParseFloat(args[1], 64)
508+
delta, _, err := big.ParseFloat(args[1], 10, 128, 0)
508509
if err != nil {
509510
setDirty(c)
510511
c.WriteError(msgInvalidFloat)
@@ -525,7 +526,7 @@ func (m *Miniredis) cmdIncrbyfloat(c *server.Peer, cmd string, args []string) {
525526
return
526527
}
527528
// Don't touch TTL
528-
c.WriteBulk(formatFloat(v))
529+
c.WriteBulk(formatBig(v))
529530
})
530531
}
531532

db.go

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package miniredis
22

33
import (
44
"errors"
5+
"math/big"
56
"sort"
67
"strconv"
78
"time"
@@ -164,17 +165,18 @@ func (db *RedisDB) stringIncr(k string, delta int) (int, error) {
164165
}
165166

166167
// change float key value
167-
func (db *RedisDB) stringIncrfloat(k string, delta float64) (float64, error) {
168-
v := 0.0
168+
func (db *RedisDB) stringIncrfloat(k string, delta *big.Float) (*big.Float, error) {
169+
v := big.NewFloat(0.0)
170+
v.SetPrec(128)
169171
if sv, ok := db.stringKeys[k]; ok {
170172
var err error
171-
v, err = strconv.ParseFloat(sv, 64)
173+
v, _, err = big.ParseFloat(sv, 10, 128, 0)
172174
if err != nil {
173-
return 0, ErrFloatValueError
175+
return nil, ErrFloatValueError
174176
}
175177
}
176-
v += delta
177-
db.stringSet(k, formatFloat(v))
178+
v.Add(v, delta)
179+
db.stringSet(k, formatBig(v))
178180
return v, nil
179181
}
180182

@@ -346,19 +348,20 @@ func (db *RedisDB) hashIncr(key, field string, delta int) (int, error) {
346348
}
347349

348350
// hashIncrfloat changes float key value
349-
func (db *RedisDB) hashIncrfloat(key, field string, delta float64) (float64, error) {
350-
v := 0.0
351+
func (db *RedisDB) hashIncrfloat(key, field string, delta *big.Float) (*big.Float, error) {
352+
v := big.NewFloat(0.0)
353+
v.SetPrec(128)
351354
if h, ok := db.hashKeys[key]; ok {
352355
if f, ok := h[field]; ok {
353356
var err error
354-
v, err = strconv.ParseFloat(f, 64)
357+
v, _, err = big.ParseFloat(f, 10, 128, 0)
355358
if err != nil {
356-
return 0, ErrFloatValueError
359+
return nil, ErrFloatValueError
357360
}
358361
}
359362
}
360-
v += delta
361-
db.hashSet(key, field, formatFloat(v))
363+
v.Add(v, delta)
364+
db.hashSet(key, field, formatBig(v))
362365
return v, nil
363366
}
364367

direct.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package miniredis
44

55
import (
66
"errors"
7+
"math/big"
78
"time"
89
)
910

@@ -148,7 +149,12 @@ func (db *RedisDB) Incrfloat(k string, delta float64) (float64, error) {
148149
return 0, ErrWrongType
149150
}
150151

151-
return db.stringIncrfloat(k, delta)
152+
v, err := db.stringIncrfloat(k, big.NewFloat(delta))
153+
if err != nil {
154+
return 0, err
155+
}
156+
vf, _ := v.Float64()
157+
return vf, nil
152158
}
153159

154160
// List returns the list k, or an error if it's not there or something else.
@@ -534,7 +540,12 @@ func (db *RedisDB) HIncrfloat(k, f string, delta float64) (float64, error) {
534540
defer db.master.Unlock()
535541
defer db.master.signal.Broadcast()
536542

537-
return db.hashIncrfloat(k, f, delta)
543+
v, err := db.hashIncrfloat(k, f, big.NewFloat(delta))
544+
if err != nil {
545+
return 0, err
546+
}
547+
vf, _ := v.Float64()
548+
return vf, nil
538549
}
539550

540551
// SRem removes fields from a set. Returns number of deleted fields.

redis.go

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package miniredis
33
import (
44
"fmt"
55
"math"
6+
"math/big"
67
"strings"
78
"sync"
89
"time"
@@ -130,16 +131,28 @@ func blocking(
130131

131132
// formatFloat formats a float the way redis does (sort-of)
132133
func formatFloat(v float64) string {
133-
// Format with %f and strip trailing 0s. This is the most like Redis does
134-
// it :(
135-
// .12 is the magic number where most output is the same as Redis.
136-
if math.IsInf(v, +1) {
134+
if math.IsInf(v, 1) {
137135
return "inf"
138136
}
139137
if math.IsInf(v, -1) {
140138
return "-inf"
141139
}
142-
sv := fmt.Sprintf("%.12f", v)
140+
return stripZeros(fmt.Sprintf("%.12f", v))
141+
}
142+
143+
// formatBig formats a float the way redis does
144+
func formatBig(v *big.Float) string {
145+
// Format with %f and strip trailing 0s.
146+
if v.IsInf() {
147+
return "inf"
148+
}
149+
// if math.IsInf(v, -1) {
150+
// return "-inf"
151+
// }
152+
return stripZeros(fmt.Sprintf("%.17f", v))
153+
}
154+
155+
func stripZeros(sv string) string {
143156
for strings.Contains(sv, ".") {
144157
if sv[len(sv)-1] != '0' {
145158
break

0 commit comments

Comments
 (0)