Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

encoding/json 314line isEmptyValue() when float64 compares with 0, '==' is likely to be false #28111

Closed
fwhezfwhez opened this issue Oct 10, 2018 · 2 comments

Comments

@fwhezfwhez
Copy link

fwhezfwhez commented Oct 10, 2018

What did you do?

I've ever faced a float comparing with 0 problem.When I did:

func f(arg interface{}){
    switch v:=arg.(type) {
    case float32,float64:
        fmt.Println(v==0)
    }
}
func main(){
    f(0.)
}

The result turns out to be false.
I fix it by

	case float32:
		r := float64(v)
		fmt.Println(math.Abs(r-0) < 0.0000001)
	case float64:
		fmt.Println(math.Abs(v-0) < 0.0000001)

OK,Things above is not what I want to ask.The point is, I see this part in encoding/json 314 line

func isEmptyValue(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
		return v.Len() == 0
	case reflect.Bool:
		return !v.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return v.Float() == 0
	case reflect.Interface, reflect.Ptr:
		return v.IsNil()
	}
	return false
}

should it be modified as

return math.Abs(v.Float()-0)<0.0000001

?

What did you expect to see?

What did you see instead?

System details

go version go1.11 windows/amd64
GOARCH="amd64"
GOBIN=""
GOCACHE="C:\Users\DELL\AppData\Local\go-build"
GOEXE=".exe"
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="windows"
GOOS="windows"
GOPATH="G:\go_workspace\GOPATH;"
GOPROXY=""
GORACE=""
GOROOT="E:\go_1.11"
GOTMPDIR=""
GOTOOLDIR="E:\go_1.11\pkg\tool\windows_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
GOROOT/bin/go version: go version go1.11 windows/amd64
GOROOT/bin/go tool compile -V: compile version go1.11
gdb --version: GNU gdb (GDB) 7.8
@elagergren-spideroak
Copy link

elagergren-spideroak commented Oct 11, 2018

The reason you're seeing an issue here is using two types in a case makes the type interface{}, not either float32 or float64 depending on the context.

From the spec:

Given an expression x of type interface{}, the following type switch:

switch i := x.(type) {
case nil:
	printString("x is nil")                // type of i is type of x (interface{})
case int:
	printInt(i)                            // type of i is int
case float64:
	printFloat64(i)                        // type of i is float64
case func(int) float64:
	printFunction(i)                       // type of i is func(int) float64
case bool, string:
	printString("type is bool or string")  // type of i is type of x (interface{})
default:
	printString("don't know the type")     // type of i is type of x (interface{})
}

You're actually comparing interface{float64(0)} to int(0), which is obviously false since the types differ. Your 'fix' can actually just compare both separate cases to 0.

isEmptyValue isn't broken because Float64 returns a float64, not interface{T}.

For example: https://play.golang.org/p/LJHI3IpzvwT

@fwhezfwhez
Copy link
Author

ok,I see.
Thanks!

@golang golang locked and limited conversation to collaborators Oct 11, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants