Как вы относитесь к сравнению с float64 в golang? - PullRequest
0 голосов
/ 23 апреля 2019

Я прохожу экскурсию по го и у меня возникла проблема со сравнением float64 в «Упражнении: цикл и функции», где вы пишете функцию для определения квадратного корня.

Из примера: Компьютеры обычно вычисляют квадратный корень из x, используя цикл. Начиная с некоторой догадки z, мы можем отрегулировать z в зависимости от того, насколько близко z² к x, создавая более точную догадку:

z -= (z*z - x) / (2*z)

Я написал функцию, которая продолжает обновлять z, пока значения не перестанут изменяться. Только сравнение float64 никогда не завершается неудачей, и это приводит к бесконечному циклу. Один из способов решения этих типов проблем - округление, но я не уверен, как это сделать в golang без использования математического модуля.

Как округлить числа с плавающей точкой в ​​golang и каков стандартный способ сравнения чисел с плавающей запятой в golang?


package main

import (
    "fmt"
)


func Sqrt(x float64) float64 {
    // Need to look into float rounding in go
    z := 1.0
    zprev := 0.01
    for z != zprev {
        zprev = z
        z -= (z*z - x) /(2*z)
        fmt.Printf("z: %g\nzprev: %g\n", z, zprev)
        fmt.Println("_________________________________________")


    }
    fmt.Println("Finished")
    return z
}


func main() {
    fmt.Println(Sqrt(2))
}

Выход:

z: 1.5
zprev: 1
_________________________________________
z: 1.4166666666666667
zprev: 1.5
_________________________________________
z: 1.4142156862745099
zprev: 1.4166666666666667
_________________________________________
z: 1.4142135623746899
zprev: 1.4142156862745099
_________________________________________
z: 1.4142135623730951
zprev: 1.4142135623746899
_________________________________________
z: 1.414213562373095
zprev: 1.4142135623730951
_________________________________________
z: 1.4142135623730951
zprev: 1.414213562373095
_________________________________________
z: 1.414213562373095
zprev: 1.4142135623730951
_________________________________________
z: 1.4142135623730951
zprev: 1.414213562373095
_________________________________________
z: 1.414213562373095
zprev: 1.4142135623730951
_________________________________________

После того, как точки z и zprev продолжают чередоваться между 2 значениями, которые отключены только на одну точку точности (1.414213562373095 и 1.4142135623730951) бесконечно

Ответы [ 3 ]

3 голосов
/ 24 апреля 2019

Вместо округления возьмите разницу между двумя числами, которые вы хотите сравнить, и убедитесь, что она находится между -epsilon и epsilon, где epsilon - это то, что вы считаете достаточно малой разницей.

Примечание: Ненадежные сравнения на равенство не являются специфическими для каждого;это универсальная проблема с числами с плавающей точкой.

2 голосов
/ 24 апреля 2019

Вот как я это сделаю - если вы вообще не хотите использовать пакет math.

package main

import "fmt"

func abs(x float64) float64 {
    if x < 0 {
        return -x
    }
    return x
}

func Sqrt(x float64) float64 {
    z := x
    var zprev float64
    for abs(zprev-z) > 1e-6 {
        zprev, z = z, z-(z*z-x)/(2*z)
    }
    return z
}

func main() {
    fmt.Println(Sqrt(2))
}

Выход:

1.4142135623730951
0 голосов
/ 24 апреля 2019

Я обнаружил, что решением этой проблемы было добавление одного из значений в сравнение к обеим сторонам сравнения.

Ниже я добавил z к обеим сторонам сравнения, и сравнение теперь работаеткак и ожидалось.

package main

import (
    "fmt"
)


func Sqrt(x float64) float64 {
    // Need to look into float rounding in go
    z := 1.0
    zprev := 0.01
    for zprev + z != z + z {
        zprev = z
        z -= (z*z - x) /(2*z)
        fmt.Printf("z: %g\nzprev: %g\n", z, zprev)
        fmt.Println("_________________________________________")

    }
    fmt.Println("Finished")
    return z
}

Вывод:

z: 1.5
zprev: 1
_________________________________________
z: 1.4166666666666667
zprev: 1.5
_________________________________________
z: 1.4142156862745099
zprev: 1.4166666666666667
_________________________________________
z: 1.4142135623746899
zprev: 1.4142156862745099
_________________________________________
z: 1.4142135623730951
zprev: 1.4142135623746899
_________________________________________
z: 1.414213562373095
zprev: 1.4142135623730951
_________________________________________
z: 1.4142135623730951
zprev: 1.414213562373095
_________________________________________
Finished
1.4142135623730951
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...