Skip to content

Commit

Permalink
Merge pull request #116 from alicebob/big
Browse files Browse the repository at this point in the history
use 128 bit floats internally
  • Loading branch information
alicebob authored Nov 20, 2019
2 parents 95e8f45 + cd51018 commit 0a9f320
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 23 deletions.
5 changes: 3 additions & 2 deletions cmd_hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package miniredis

import (
"math/big"
"strconv"
"strings"

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

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

delta, err := strconv.ParseFloat(deltas, 64)
delta, _, err := big.ParseFloat(deltas, 10, 128, 0)
if err != nil {
setDirty(c)
c.WriteError(msgInvalidFloat)
Expand All @@ -518,7 +519,7 @@ func (m *Miniredis) cmdHincrbyfloat(c *server.Peer, cmd string, args []string) {
c.WriteError(err.Error())
return
}
c.WriteBulk(formatFloat(v))
c.WriteBulk(formatBig(v))
})
}

Expand Down
5 changes: 3 additions & 2 deletions cmd_string.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package miniredis

import (
"math/big"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -504,7 +505,7 @@ func (m *Miniredis) cmdIncrbyfloat(c *server.Peer, cmd string, args []string) {
}

key := args[0]
delta, err := strconv.ParseFloat(args[1], 64)
delta, _, err := big.ParseFloat(args[1], 10, 128, 0)
if err != nil {
setDirty(c)
c.WriteError(msgInvalidFloat)
Expand All @@ -525,7 +526,7 @@ func (m *Miniredis) cmdIncrbyfloat(c *server.Peer, cmd string, args []string) {
return
}
// Don't touch TTL
c.WriteBulk(formatFloat(v))
c.WriteBulk(formatBig(v))
})
}

Expand Down
27 changes: 15 additions & 12 deletions db.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package miniredis

import (
"errors"
"math/big"
"sort"
"strconv"
"time"
Expand Down Expand Up @@ -164,17 +165,18 @@ func (db *RedisDB) stringIncr(k string, delta int) (int, error) {
}

// change float key value
func (db *RedisDB) stringIncrfloat(k string, delta float64) (float64, error) {
v := 0.0
func (db *RedisDB) stringIncrfloat(k string, delta *big.Float) (*big.Float, error) {
v := big.NewFloat(0.0)
v.SetPrec(128)
if sv, ok := db.stringKeys[k]; ok {
var err error
v, err = strconv.ParseFloat(sv, 64)
v, _, err = big.ParseFloat(sv, 10, 128, 0)
if err != nil {
return 0, ErrFloatValueError
return nil, ErrFloatValueError
}
}
v += delta
db.stringSet(k, formatFloat(v))
v.Add(v, delta)
db.stringSet(k, formatBig(v))
return v, nil
}

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

// hashIncrfloat changes float key value
func (db *RedisDB) hashIncrfloat(key, field string, delta float64) (float64, error) {
v := 0.0
func (db *RedisDB) hashIncrfloat(key, field string, delta *big.Float) (*big.Float, error) {
v := big.NewFloat(0.0)
v.SetPrec(128)
if h, ok := db.hashKeys[key]; ok {
if f, ok := h[field]; ok {
var err error
v, err = strconv.ParseFloat(f, 64)
v, _, err = big.ParseFloat(f, 10, 128, 0)
if err != nil {
return 0, ErrFloatValueError
return nil, ErrFloatValueError
}
}
}
v += delta
db.hashSet(key, field, formatFloat(v))
v.Add(v, delta)
db.hashSet(key, field, formatBig(v))
return v, nil
}

Expand Down
15 changes: 13 additions & 2 deletions direct.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package miniredis

import (
"errors"
"math/big"
"time"
)

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

return db.stringIncrfloat(k, delta)
v, err := db.stringIncrfloat(k, big.NewFloat(delta))
if err != nil {
return 0, err
}
vf, _ := v.Float64()
return vf, nil
}

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

return db.hashIncrfloat(k, f, delta)
v, err := db.hashIncrfloat(k, f, big.NewFloat(delta))
if err != nil {
return 0, err
}
vf, _ := v.Float64()
return vf, nil
}

// SRem removes fields from a set. Returns number of deleted fields.
Expand Down
23 changes: 18 additions & 5 deletions redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package miniredis
import (
"fmt"
"math"
"math/big"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -130,16 +131,28 @@ func blocking(

// formatFloat formats a float the way redis does (sort-of)
func formatFloat(v float64) string {
// Format with %f and strip trailing 0s. This is the most like Redis does
// it :(
// .12 is the magic number where most output is the same as Redis.
if math.IsInf(v, +1) {
if math.IsInf(v, 1) {
return "inf"
}
if math.IsInf(v, -1) {
return "-inf"
}
sv := fmt.Sprintf("%.12f", v)
return stripZeros(fmt.Sprintf("%.12f", v))
}

// formatBig formats a float the way redis does
func formatBig(v *big.Float) string {
// Format with %f and strip trailing 0s.
if v.IsInf() {
return "inf"
}
// if math.IsInf(v, -1) {
// return "-inf"
// }
return stripZeros(fmt.Sprintf("%.17f", v))
}

func stripZeros(sv string) string {
for strings.Contains(sv, ".") {
if sv[len(sv)-1] != '0' {
break
Expand Down

0 comments on commit 0a9f320

Please sign in to comment.