Leetcode Note: Go - Valid Perfect Square
Valid Perfect Square - LeetCode
https://leetcode.com/problems/valid-perfect-square/
- Go 言語で取り組んだメモ
所感
- 与えられた int 数値が perfect square であれば true を return する
- perfect square は完全平方のこと
- 他の整数の平方(二乗)になっている整数
- 例: 1 (1^2), 4 (2^2), 9 (3^2), 16 (4^2), 25 (5^2), …
- 標準ライブラリの sqrt 的なものは使わずに実装する
回答
[GO] Newton’s Method Solution - LeetCode Discuss
https://leetcode.com/problems/valid-perfect-square/discuss/559495/GO-Newton's-Method-Solution
func isPerfectSquare(num int) bool {
if num < 2 {
return true
}
x := num / 2
for x*x > num {
x = (x + num/x) / 2
}
return x*x == num
}
- newton’s method という解法で完全平方を求める実装
- ニュートン法 - Wikipedia
- そもそも root を求めるアルゴリズムがいくつかあり、そのうちの 1つ という感じらしい
- x に num / 2 を初期値としてセット
x * x
が num 以上の間ループ- x に
(x + num/x) / 2
を代入- よくわからないので具体的な数値をシミュレーションして考えてみる
- case num == 6:
- x := 6 / 2
- 3 * 3 > 6 == true なのでループ処理突入
- x = (3 + 6 / 3) / 2 なので 3 / 2 で 1 が代入される
- 1 * 1 > 6 == false なのでループ脱出
- 1 * 1 == 6 は false なので完全平方では無い
- case num == 16:
- x := 16 / 2
- 8 * 8 > 16 == false なのでループ入らず
- 8 * 8 == 16 は true なので完全平方
- シミュレーションしても良くわらないが成立している
- 数学力よ・・・
- x に
x*x == num
が成立するなら完全平方
標準ライブラリの Sqrt 調査
https://github.com/golang/go/blob/go1.18.3/src/math/sqrt.go
// Sqrt returns the square root of x.
//
// Special cases are:
// Sqrt(+Inf) = +Inf
// Sqrt(±0) = ±0
// Sqrt(x < 0) = NaN
// Sqrt(NaN) = NaN
func Sqrt(x float64) float64 {
if haveArchSqrt {
return archSqrt(x)
}
return sqrt(x)
}
// Note: Sqrt is implemented in assembly on some systems.
// Others have assembly stubs that jump to func sqrt below.
// On systems where Sqrt is a single instruction, the compiler
// may turn a direct call into a direct use of that instruction instead.
func sqrt(x float64) float64 {
// special cases
switch {
case x == 0 || IsNaN(x) || IsInf(x, 1):
return x
case x < 0:
return NaN()
}
ix := Float64bits(x)
// normalize x
exp := int((ix >> shift) & mask)
if exp == 0 { // subnormal x
for ix&(1<<shift) == 0 {
ix <<= 1
exp--
}
exp++
}
exp -= bias // unbias exponent
ix &^= mask << shift
ix |= 1 << shift
if exp&1 == 1 { // odd exp, double x to make it even
ix <<= 1
}
exp >>= 1 // exp = exp/2, exponent of square root
// generate sqrt(x) bit by bit
ix <<= 1
var q, s uint64 // q = sqrt(x)
r := uint64(1 << (shift + 1)) // r = moving bit from MSB to LSB
for r != 0 {
t := s + r
if t <= ix {
s = t + r
ix -= t
q += r
}
ix <<= 1
r >>= 1
}
// final rounding
if ix != 0 { // remainder, result not exact
q += q & 1 // round according to extra bit
}
ix = q>>1 + uint64(exp-1+bias)<<shift // significand + biased exponent
return Float64frombits(ix)
}
システム毎にアセンブリで実装しているらしい?