I imported the math library in my program, and I was trying to find the minimum of three numbers in the following way:
v1[j+1] = math.Min(v1[j]+1, math.Min(v0[j+1]+1, v0[j]+cost))
where v1 is declared as:
t := "stackoverflow" v1 := make([]int, len(t)+1)
However, when I run my program I get the following error:
./levenshtein_distance.go:36: cannot use int(v0[j + 1] + 1) (type int) as type float64 in argument to math.Min
I thought it was weird because I have another program where I write
fmt.Println(math.Min(2,3))
and that program outputs 2
without complaining.
so I ended up casting the values as float64, so that math.Min
could work:
v1[j+1] = math.Min(float64(v1[j]+1), math.Min(float64(v0[j+1]+1), float64(v0[j]+cost)))
With this approach, I got the following error:
./levenshtein_distance.go:36: cannot use math.Min(int(v1[j] + 1), math.Min(int(v0[j + 1] + 1), int(v0[j] + cost))) (type float64) as type int in assignment
so to get rid of the problem, I just casted the result back to int
I thought this was extremely inefficient and hard to read:
v1[j+1] = int(math.Min(float64(v1[j]+1), math.Min(float64(v0[j+1]+1), float64(v0[j]+cost))))
I also wrote a small minInt
function, but I think this should be unnecessary because the other programs that make use of math.Min
work just fine when taking integers, so I concluded this has to be a problem of my program and not the library per se.
Is there anything that I'm doing terrible wrong?
Here's a program that you can use to reproduce the issues above, line 36 specifically: package main
import ( "math" ) func main() { LevenshteinDistance("stackoverflow", "stackexchange") } func LevenshteinDistance(s string, t string) int { if s == t { return 0 } if len(s) == 0 { return len(t) } if len(t) == 0 { return len(s) } v0 := make([]int, len(t)+1) v1 := make([]int, len(t)+1) for i := 0; i < len(v0); i++ { v0[i] = i } for i := 0; i < len(s); i++ { v1[0] = i + 1 for j := 0; j < len(t); j++ { cost := 0 if s[i] != t[j] { cost = 1 } v1[j+1] = int(math.Min(float64(v1[j]+1), math.Min(float64(v0[j+1]+1), float64(v0[j]+cost)))) } for j := 0; j < len(v0); j++ { v0[j] = v1[j] } } return v1[len(t)] }
Nope, I think writing something like that is fine: for instance, the stdlib's sort.go does it near the top of the file:
func min(a, b int) int { if a < b { return a } return b }
math.Min(2, 3)
happened to work because numeric constants in Go are untyped. Beware of treating float64s as a universal number type in general, though, since integers above 2^53
will get rounded if converted to float64.
Although it does not work on stable Go as I'm writing this, in the Go 1.18 beta you can write a generic min
function which is just as efficient at run time as the hand-coded single-type version.
There's been discussion of updating the stdlib to add generic versions of existing functions, but if that happens it won't be until a later version.
There is no built-in min or max function for integers, but it’s simple to write your own. Thanks to support for variadic functions we can even compare more integers with just one call:
func MinOf(vars ...int) int { min := vars[0] for _, i := range vars { if min > i { min = i } } return min }
Usage:
MinOf(3, 9, 6, 2)
Similarly here is the max function:
func MaxOf(vars ...int) int { max := vars[0] for _, i := range vars { if max < i { max = i } } return max }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With