//
// x and y are both assumed to be in the range [0, 0xffff].
func sqDiff(x, y uint32) uint32 {
- var d uint32
- if x > y {
- d = x - y
- } else {
- d = y - x
- }
+ // The canonical code of this function looks as follows:
+ //
+ // var d uint32
+ // if x > y {
+ // d = x - y
+ // } else {
+ // d = y - x
+ // }
+ // return (d * d) >> 2
+ //
+ // Language spec guarantees the following properties of unsigned integer
+ // values operations with respect to overflow/wrap around:
+ //
+ // > For unsigned integer values, the operations +, -, *, and << are
+ // > computed modulo 2n, where n is the bit width of the unsigned
+ // > integer's type. Loosely speaking, these unsigned integer operations
+ // > discard high bits upon overflow, and programs may rely on ``wrap
+ // > around''.
+ //
+ // Considering these properties and the fact that this function is
+ // called in the hot paths (x,y loops), it is reduced to the below code
+ // which is slightly faster. See TestSqDiff for correctness check.
+ d := x - y
return (d * d) >> 2
}
--- /dev/null
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package color
+
+import (
+ "testing"
+ "testing/quick"
+)
+
+func TestSqDiff(t *testing.T) {
+ // canonical sqDiff implementation
+ orig := func(x, y uint32) uint32 {
+ var d uint32
+ if x > y {
+ d = uint32(x - y)
+ } else {
+ d = uint32(y - x)
+ }
+ return (d * d) >> 2
+ }
+ testCases := []uint32{
+ 0,
+ 1,
+ 2,
+ 0x0fffd,
+ 0x0fffe,
+ 0x0ffff,
+ 0x10000,
+ 0x10001,
+ 0x10002,
+ 0xfffffffd,
+ 0xfffffffe,
+ 0xffffffff,
+ }
+ for _, x := range testCases {
+ for _, y := range testCases {
+ if got, want := sqDiff(x, y), orig(x, y); got != want {
+ t.Fatalf("sqDiff(%#x, %#x): got %d, want %d", x, y, got, want)
+ }
+ }
+ }
+ if err := quick.CheckEqual(orig, sqDiff, &quick.Config{MaxCountScale: 10}); err != nil {
+ t.Fatal(err)
+ }
+}
//
// x and y are both assumed to be in the range [0, 0xffff].
func sqDiff(x, y int32) uint32 {
- var d uint32
- if x > y {
- d = uint32(x - y)
- } else {
- d = uint32(y - x)
- }
+ // This is an optimized code relying on the overflow/wrap around
+ // properties of unsigned integers operations guaranteed by the language
+ // spec. See sqDiff from the image/color package for more details.
+ d := uint32(x - y)
return (d * d) >> 2
}
"image/png"
"os"
"testing"
+ "testing/quick"
)
func eq(c0, c1 color.Color) bool {
}
}
}
+
+func TestSqDiff(t *testing.T) {
+ // This test is similar to the one from the image/color package, but
+ // sqDiff in this package accepts int32 instead of uint32, so test it
+ // for appropriate input.
+
+ // canonical sqDiff implementation
+ orig := func(x, y int32) uint32 {
+ var d uint32
+ if x > y {
+ d = uint32(x - y)
+ } else {
+ d = uint32(y - x)
+ }
+ return (d * d) >> 2
+ }
+ testCases := []int32{
+ 0,
+ 1,
+ 2,
+ 0x0fffd,
+ 0x0fffe,
+ 0x0ffff,
+ 0x10000,
+ 0x10001,
+ 0x10002,
+ 0x7ffffffd,
+ 0x7ffffffe,
+ 0x7fffffff,
+ -0x7ffffffd,
+ -0x7ffffffe,
+ -0x80000000,
+ }
+ for _, x := range testCases {
+ for _, y := range testCases {
+ if got, want := sqDiff(x, y), orig(x, y); got != want {
+ t.Fatalf("sqDiff(%#x, %#x): got %d, want %d", x, y, got, want)
+ }
+ }
+ }
+ if err := quick.CheckEqual(orig, sqDiff, &quick.Config{MaxCountScale: 10}); err != nil {
+ t.Fatal(err)
+ }
+}