Golang 运行时除数为 0 返回 Inf

在 Golang 中,除数为 0 时,常规情况下是无法编译通过的,但是如果除数是由运行时决定的,那么为除数为 0 时则不会 panic,而是实现为 IEEE 754 标准,返回 Inf。

The result of a floating-point or complex division by zero is not specified beyond the IEEE-754 standard; whether a run-time panic occurs is implementation-specific.

IEEE 754 specifies five arithmetic exceptions that are to be recorded in the status flags (“sticky bits”):

inexact, set if the rounded (and returned) value is different from the mathematically exact result of the operation. underflow, set if the rounded value is tiny (as specified in IEEE 754) and inexact (or maybe limited to if it has denormalization loss, as per the 1984 version of IEEE 754), returning a subnormal value including the zeros. overflow, set if the absolute value of the rounded value is too large to be represented. An infinity or maximal finite value is returned, depending on which rounding is used. divide-by-zero, set if the result is infinite given finite operands, returning an infinity, either +∞ or −∞. invalid, set if a real-valued result cannot be returned e.g. sqrt(−1) or 0/0, returning a quiet NaN.

这种情况可能导致的问题是, 如果结构体中的字段是由运行时算出为Inf,当你对这个结构体进行json序列化时,json Marshal 会返回错误:

json: unsupported value: +Inf

通过一段代码说明:

package main

import (
    "encoding/json"
    "fmt"
    "strconv"
)

func interfaceToFloat64(unk interface{}) (result float64) {
    switch i := unk.(type) {
    case float64:
        result = float64(i)
    case float32:
        result = float64(i)
    case int64:
        result = float64(i)
    case int32:
        result = float64(i)
    case int:
        result = float64(i)
    case uint32:
        result = float64(i)
    case uint64:
        result = float64(i)
    case uint:
        result = float64(i)
    case string:
        if i == "" || i == "--" {
            result = 0.0
        } else {
            result, _ = strconv.ParseFloat(i, 64)

        }
    default:
        result = 0.0
    }

    return
}

func main() {
    var (
        a interface{} = 1
        b interface{} = 0
    )

    x := interfaceToFloat64(a) / interfaceToFloat64(b)
    fmt.Println("x:", x)

    type T struct {
        F float64
    }
    t := T{
        F: x,
    }
    fmt.Printf("t: %+v\n", t)

    _, err := json.Marshal(t)
    fmt.Println("err:", err)

}

运行后输出结果:

x: +Inf
t: {F:+Inf}
err: json: unsupported value: +Inf

对于 golang json 序列化 Inf 失败的解决方法,可以通过判断其是否为 Inf,并将其设为特定值来解决,如:

//  runtime 1.0 / 0.0 is +Inf
if math.IsNaN(x) || math.IsInf(x, 0) {
    x = 0.0
}

参考文档:

golang 

也可以看看