blob: 7ddd3a1d21c82d1653af7c585efaedbec4155129 [file] [log] [blame]
//
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package noise
import (
"math"
"testing"
)
func TestCeilPowerOfTwoInputIsNotInDomain(t *testing.T) {
for _, x := range []float64{
0.0,
-1.0,
math.Inf(-1),
math.Inf(1),
math.NaN(),
math.MaxFloat64,
math.Pow(2.001, 1023.0),
} {
if got := ceilPowerOfTwo(x); !math.IsNaN(got) {
t.Errorf("ceilPowerOfTwo(%f) = %f, want NaN", x, got)
}
}
}
func TestCeilPowerOfTwoInputIsPowerOfTwo(t *testing.T) {
// Verify that CeilPowerOfTwo returns its input if the input is a power
// of 2. The test is done exhaustively for all possible exponents of a
// float64 value.
for exponent := -1022.0; exponent <= 1023; exponent++ {
x := math.Pow(2.0, exponent)
got := ceilPowerOfTwo(x)
want := x
if got != want {
t.Errorf("ceilPowerOfTwo(%f) = %f, want %f", x, got, want)
}
}
}
func TestCeilPowerOfTwoInputIsNotPowerOfTwo(t *testing.T) {
// Verify that CeilPowerOfTwo returns the next power of two for inputs
// that are different from a power of 2. The test is done exhaustively
// for all possible exponents of a float64 value.
for exponent := -1022.0; exponent <= -1.0; exponent++ {
x := math.Pow(2.001, exponent)
got := ceilPowerOfTwo(x)
want := math.Pow(2.0, exponent)
if got != want {
t.Errorf("ceilPowerOfTwo(%f) = %f, want %f", x, got, want)
}
}
x := 0.99
got := ceilPowerOfTwo(x)
want := 1.0
if got != want {
t.Errorf("ceilPowerOfTwo(%f) = %f, want %f", x, got, want)
}
for exponent := 1.0; exponent <= 1022.0; exponent++ {
x := math.Pow(2.001, exponent)
got := ceilPowerOfTwo(x)
want := math.Pow(2.0, exponent+1)
if got != want {
t.Errorf("ceilPowerOfTwo(%f) = %f, want %f", x, got, want)
}
}
}
func TestRoundToMultipleOfPowerOfTwoXIsAMultiple(t *testing.T) {
// Verify that RoundToMultipleOfPowerOfTwo returns x if x is a
// multiple of granularity.
for _, tc := range []struct {
x float64
granularity float64
want float64
}{
{
x: 0.0,
granularity: 0.5,
want: 0.0,
},
{
x: 0.125,
granularity: 0.125,
want: 0.125,
},
{
x: -0.125,
granularity: 0.125,
want: -0.125,
},
{
x: 16512.0,
granularity: 1.0,
want: 16512.0,
},
{
x: -16512.0,
granularity: 1.0,
want: -16512.0,
},
{
x: 3936.0,
granularity: 32.0,
want: 3936.0,
},
{
x: -3936.0,
granularity: 32.0,
want: -3936.0,
},
{
x: 7.9990234375,
granularity: 0.0009765625,
want: 7.9990234375,
},
{
x: -7.9990234375,
granularity: 0.0009765625,
want: -7.9990234375,
},
{
x: float64(math.MaxInt64),
granularity: 0.125,
want: float64(math.MaxInt64),
},
{
x: float64(math.MinInt64),
granularity: 0.125,
want: float64(math.MinInt64),
},
} {
got := roundToMultipleOfPowerOfTwo(tc.x, tc.granularity)
if got != tc.want {
t.Errorf(
"roundToMultipleOfPowerOfTwo(%f, %f) = %f, want %f",
tc.x,
tc.granularity,
got,
tc.want,
)
}
}
}
func TestRoundToMultipleOfPowerOfTwoXIsNotAMultiple(t *testing.T) {
// Verify that RoundToMultipleOfPowerOfTwo returns the next closest
// multiple of granularity if x is not already a multiple.
for _, tc := range []struct {
x float64
granularity float64
want float64
}{
{
x: 0.124,
granularity: 0.125,
want: 0.125,
},
{
x: -0.124,
granularity: 0.125,
want: -0.125,
},
{
x: 0.126,
granularity: 0.125,
want: 0.125,
},
{
x: -0.126,
granularity: 0.125,
want: -0.125,
},
{
x: 16512.499,
granularity: 1.0,
want: 16512.0,
},
{
x: -16512.499,
granularity: 1.0,
want: -16512.0,
},
{
x: 16511.501,
granularity: 1.0,
want: 16512.0,
},
{
x: -16511.501,
granularity: 1.0,
want: -16512.0,
},
{
x: 3920.3257,
granularity: 32.0,
want: 3936.0,
},
{
x: -3920.3257,
granularity: 32.0,
want: -3936.0,
},
{
x: 3951.7654,
granularity: 32.0,
want: 3936.0,
},
{
x: -3951.7654,
granularity: 32.0,
want: -3936.0,
},
{
x: 7.9990232355,
granularity: 0.0009765625,
want: 7.9990234375,
},
{
x: -7.9990232355,
granularity: 0.0009765625,
want: -7.9990234375,
},
{
x: 7.9990514315,
granularity: 0.0009765625,
want: 7.9990234375,
},
{
x: -7.9990514315,
granularity: 0.0009765625,
want: -7.9990234375,
},
} {
got := roundToMultipleOfPowerOfTwo(tc.x, tc.granularity)
if got != tc.want {
t.Errorf(
"roundToMultipleOfPowerOfTwo(%f, %f) = %f, want %f",
tc.x,
tc.granularity,
got,
tc.want,
)
}
}
}
func TestNextLargerFloat64InputRepresentableAsFloat64(t *testing.T) {
// Verify that nextLargerFloat64 returns a float64 of the same value.
for _, x := range []int64{
0,
1,
-1,
// Smallest positive float64 for which next float64 is a distance of 2 away.
9007199254740992,
// Largest negative float64 for which previous float64 is a distance of 2 away.
-9007199254740992,
// Arbitrary representable number.
8646911284551352320,
-8646911284551352320,
// Largest int64 value accurately representable as a float64.
math.MaxInt64 - 1023,
// Smallest int64 value accurately representable as a float64.
math.MinInt64,
} {
got := int64(nextLargerFloat64(x))
if got != x {
t.Errorf("nextLargerFloat64(%d) = %d, want %d", x, got, x)
}
}
}
func TestNextLargerFloat64InputNotRepresentableAsFloat64(t *testing.T) {
// Verify that nextLargerFloat64 computes the smallest float64 value that is larger than
// or equal to the provided int64 value.
for _, tc := range []struct {
n int64
want int64
}{
// Smallest positive int64 value not representable as a float64.
{n: 9007199254740993, want: 9007199254740994},
// Largest negative int64 value not representable as a float64.
{n: -9007199254740993, want: -9007199254740992},
// Testing non-representable int64 values that lie between arbitrary float64 gap.
{n: 8646911284551352321, want: 8646911284551353344},
{n: 8646911284551353343, want: 8646911284551353344},
{n: -8646911284551352321, want: -8646911284551352320},
{n: -8646911284551353343, want: -8646911284551352320},
} {
got := int64(nextLargerFloat64(tc.n))
if got != tc.want {
t.Errorf("nextLargerFloat64(%d) = %d, want %d", tc.n, got, tc.want)
}
}
// Casting math.MaxInt64 to float64 should result in the next larger float64, i.e 2^63.
// This equality has to be done in float64.
got := nextLargerFloat64(math.MaxInt64)
want := float64(1 << 63)
if got != want {
t.Errorf("nextLargerFloat64(%d) = %f, want %f", math.MaxInt64, got, want)
}
}
func TestNextSmallerFloat64InputRepresentableAsFloat64(t *testing.T) {
// Verify that nextSmallerFloat64 returns a float64 of the same value.
for _, x := range []int64{
0,
1,
-1,
// Smallest positive float64 for which next float64 is a distance of 2 away.
9007199254740992,
// Largest negative float64 for which previous float64 is a distance of 2 away.
-9007199254740992,
// Arbitrary representable number.
8646911284551352320,
-8646911284551352320,
// Largest int64 value accurately representable as a float64.
math.MaxInt64 - 1023,
// Smallest int64 value accurately representable as a float64.
math.MinInt64,
} {
got := int64(nextSmallerFloat64(x))
if got != x {
t.Errorf("nextSmallerFloat64(%d) = %d, want %d", x, got, x)
}
}
}
func TestNextSmallerFloat64InputNotRepresentableAsFloat64(t *testing.T) {
// Verify that nextSmallerFloat64 computes the largest float64 value that is smaller than
// or equal to the provided int64 value.
for _, tc := range []struct {
n int64
want int64
}{
// Smallest positive int64 value not representable as a float64.
{n: 9007199254740993, want: 9007199254740992},
// Largest negative int64 value not representable as a float64.
{n: -9007199254740993, want: -9007199254740994},
// Testing non-representable int64 values that lie between arbitrary float64 gap.
{n: 8646911284551352321, want: 8646911284551352320},
{n: 8646911284551353343, want: 8646911284551352320},
{n: -8646911284551352321, want: -8646911284551353344},
{n: -8646911284551353343, want: -8646911284551353344},
} {
got := int64(nextSmallerFloat64(tc.n))
if got != tc.want {
t.Errorf("nextSmallerFloat64(%d) = %d, want %d", tc.n, got, tc.want)
}
}
}