Applying third patch from LANG-381. Fixes the minimum(float[]) type methods to correctly return NaN when it is in the array, and adds an IEEE754rUtils class that obeys the IEEE 754r update in which NaN in min/max methods should be ignored unless all values are NaN.

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@609475 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Henri Yandell 2008-01-06 23:58:59 +00:00
parent ea4ce16289
commit bee5b923c5
4 changed files with 359 additions and 0 deletions

View File

@ -0,0 +1,265 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.commons.lang.math;
/**
* <p>Provides IEEE-754r variants of NumberUtils methods. </p>
*
* <p>See: <a href="http://en.wikipedia.org/wiki/IEEE_754r">http://en.wikipedia.org/wiki/IEEE_754r</a></p>
*
* @since 2.4
* @version $Id: IEEE754rUtils.java 491076 2006-12-29 18:48:37Z bayard $
*/
public class IEEE754rUtils {
/**
* <p>Returns the minimum value in an array.</p>
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if <code>array</code> is <code>null</code>
* @throws IllegalArgumentException if <code>array</code> is empty
*/
public static double min(double[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns min
double min = array[0];
for (int i = 1; i < array.length; i++) {
min = min(array[i], min);
}
return min;
}
/**
* <p>Returns the minimum value in an array.</p>
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if <code>array</code> is <code>null</code>
* @throws IllegalArgumentException if <code>array</code> is empty
*/
public static float min(float[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns min
float min = array[0];
for (int i = 1; i < array.length; i++) {
min = min(array[i], min);
}
return min;
}
/**
* <p>Gets the minimum of three <code>double</code> values.</p>
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the smallest of the values
*/
public static double min(double a, double b, double c) {
return min(min(a, b), c);
}
/**
* <p>Gets the minimum of two <code>double</code> values.</p>
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
*
* @param a value 1
* @param b value 2
* @return the smallest of the values
*/
public static double min(double a, double b) {
if(Double.isNaN(a)) {
return b;
} else
if(Double.isNaN(b)) {
return a;
} else {
return Math.min(a, b);
}
}
/**
* <p>Gets the minimum of three <code>float</code> values.</p>
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the smallest of the values
*/
public static float min(float a, float b, float c) {
return min(min(a, b), c);
}
/**
* <p>Gets the minimum of two <code>float</code> values.</p>
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
*
* @param a value 1
* @param b value 2
* @return the smallest of the values
*/
public static float min(float a, float b) {
if(Float.isNaN(a)) {
return b;
} else
if(Float.isNaN(b)) {
return a;
} else {
return Math.min(a, b);
}
}
/**
* <p>Returns the maximum value in an array.</p>
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if <code>array</code> is <code>null</code>
* @throws IllegalArgumentException if <code>array</code> is empty
*/
public static double max(double[] array) {
// Validates input
if (array== null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns max
double max = array[0];
for (int j = 1; j < array.length; j++) {
max = max(array[j], max);
}
return max;
}
/**
* <p>Returns the maximum value in an array.</p>
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws IllegalArgumentException if <code>array</code> is <code>null</code>
* @throws IllegalArgumentException if <code>array</code> is empty
*/
public static float max(float[] array) {
// Validates input
if (array == null) {
throw new IllegalArgumentException("The Array must not be null");
} else if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty.");
}
// Finds and returns max
float max = array[0];
for (int j = 1; j < array.length; j++) {
max = max(array[j], max);
}
return max;
}
/**
* <p>Gets the maximum of three <code>double</code> values.</p>
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the largest of the values
*/
public static double max(double a, double b, double c) {
return max(max(a, b), c);
}
/**
* <p>Gets the maximum of two <code>double</code> values.</p>
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
*
* @param a value 1
* @param b value 2
* @return the largest of the values
*/
public static double max(double a, double b) {
if(Double.isNaN(a)) {
return b;
} else
if(Double.isNaN(b)) {
return a;
} else {
return Math.max(a, b);
}
}
/**
* <p>Gets the maximum of three <code>float</code> values.</p>
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the largest of the values
*/
public static float max(float a, float b, float c) {
return max(max(a, b), c);
}
/**
* <p>Gets the maximum of two <code>float</code> values.</p>
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
*
* @param a value 1
* @param b value 2
* @return the largest of the values
*/
public static float max(float a, float b) {
if(Float.isNaN(a)) {
return b;
} else
if(Float.isNaN(b)) {
return a;
} else {
return Math.max(a, b);
}
}
}

View File

@ -783,6 +783,7 @@ public class NumberUtils {
* @return the minimum value in the array * @return the minimum value in the array
* @throws IllegalArgumentException if <code>array</code> is <code>null</code> * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
* @throws IllegalArgumentException if <code>array</code> is empty * @throws IllegalArgumentException if <code>array</code> is empty
* @see IEEE754rUtils#min(double[]) IEEE754rUtils for a version of this method that handles NaN differently
*/ */
public static double min(double[] array) { public static double min(double[] array) {
// Validates input // Validates input
@ -795,6 +796,9 @@ public class NumberUtils {
// Finds and returns min // Finds and returns min
double min = array[0]; double min = array[0];
for (int i = 1; i < array.length; i++) { for (int i = 1; i < array.length; i++) {
if (Double.isNaN(array[i])) {
return Double.NaN;
}
if (array[i] < min) { if (array[i] < min) {
min = array[i]; min = array[i];
} }
@ -810,6 +814,7 @@ public class NumberUtils {
* @return the minimum value in the array * @return the minimum value in the array
* @throws IllegalArgumentException if <code>array</code> is <code>null</code> * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
* @throws IllegalArgumentException if <code>array</code> is empty * @throws IllegalArgumentException if <code>array</code> is empty
* @see IEEE754rUtils#min(float[]) IEEE754rUtils for a version of this method that handles NaN differently
*/ */
public static float min(float[] array) { public static float min(float[] array) {
// Validates input // Validates input
@ -822,6 +827,9 @@ public class NumberUtils {
// Finds and returns min // Finds and returns min
float min = array[0]; float min = array[0];
for (int i = 1; i < array.length; i++) { for (int i = 1; i < array.length; i++) {
if (Float.isNaN(array[i])) {
return Float.NaN;
}
if (array[i] < min) { if (array[i] < min) {
min = array[i]; min = array[i];
} }
@ -947,6 +955,7 @@ public class NumberUtils {
* @return the minimum value in the array * @return the minimum value in the array
* @throws IllegalArgumentException if <code>array</code> is <code>null</code> * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
* @throws IllegalArgumentException if <code>array</code> is empty * @throws IllegalArgumentException if <code>array</code> is empty
* @see IEEE754rUtils#max(double[]) IEEE754rUtils for a version of this method that handles NaN differently
*/ */
public static double max(double[] array) { public static double max(double[] array) {
// Validates input // Validates input
@ -959,6 +968,9 @@ public class NumberUtils {
// Finds and returns max // Finds and returns max
double max = array[0]; double max = array[0];
for (int j = 1; j < array.length; j++) { for (int j = 1; j < array.length; j++) {
if (Double.isNaN(array[j])) {
return Double.NaN;
}
if (array[j] > max) { if (array[j] > max) {
max = array[j]; max = array[j];
} }
@ -974,6 +986,7 @@ public class NumberUtils {
* @return the minimum value in the array * @return the minimum value in the array
* @throws IllegalArgumentException if <code>array</code> is <code>null</code> * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
* @throws IllegalArgumentException if <code>array</code> is empty * @throws IllegalArgumentException if <code>array</code> is empty
* @see IEEE754rUtils#max(float[]) IEEE754rUtils for a version of this method that handles NaN differently
*/ */
public static float max(float[] array) { public static float max(float[] array) {
// Validates input // Validates input
@ -986,6 +999,9 @@ public class NumberUtils {
// Finds and returns max // Finds and returns max
float max = array[0]; float max = array[0];
for (int j = 1; j < array.length; j++) { for (int j = 1; j < array.length; j++) {
if (Float.isNaN(array[j])) {
return Float.NaN;
}
if (array[j] > max) { if (array[j] > max) {
max = array[j]; max = array[j];
} }
@ -1078,6 +1094,7 @@ public class NumberUtils {
* @param b value 2 * @param b value 2
* @param c value 3 * @param c value 3
* @return the smallest of the values * @return the smallest of the values
* @see IEEE754rUtils#min(double, double, double) for a version of this method that handles NaN differently
*/ */
public static double min(double a, double b, double c) { public static double min(double a, double b, double c) {
return Math.min(Math.min(a, b), c); return Math.min(Math.min(a, b), c);
@ -1093,6 +1110,7 @@ public class NumberUtils {
* @param b value 2 * @param b value 2
* @param c value 3 * @param c value 3
* @return the smallest of the values * @return the smallest of the values
* @see IEEE754rUtils#min(float, float, float) for a version of this method that handles NaN differently
*/ */
public static float min(float a, float b, float c) { public static float min(float a, float b, float c) {
return Math.min(Math.min(a, b), c); return Math.min(Math.min(a, b), c);
@ -1182,6 +1200,7 @@ public class NumberUtils {
* @param b value 2 * @param b value 2
* @param c value 3 * @param c value 3
* @return the largest of the values * @return the largest of the values
* @see IEEE754rUtils#max(double, double, double) for a version of this method that handles NaN differently
*/ */
public static double max(double a, double b, double c) { public static double max(double a, double b, double c) {
return Math.max(Math.max(a, b), c); return Math.max(Math.max(a, b), c);
@ -1197,6 +1216,7 @@ public class NumberUtils {
* @param b value 2 * @param b value 2
* @param c value 3 * @param c value 3
* @return the largest of the values * @return the largest of the values
* @see IEEE754rUtils#max(float, float, float) for a version of this method that handles NaN differently
*/ */
public static float max(float a, float b, float c) { public static float max(float a, float b, float c) {
return Math.max(Math.max(a, b), c); return Math.max(Math.max(a, b), c);

View File

@ -0,0 +1,53 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.commons.lang.math;
import junit.framework.TestCase;
/**
* Unit tests {@link org.apache.commons.lang.math.IEEE754rUtils}.
*
* @version $Id: IEEE754rUtilsTest.java 583665 2007-10-11 01:34:13Z ggregory $
*/
public class IEEE754rUtilsTest extends TestCase {
public void testLang381() {
assertEquals(1.2, IEEE754rUtils.min(1.2, 2.5, Double.NaN), 0.01);
assertEquals(2.5, IEEE754rUtils.max(1.2, 2.5, Double.NaN), 0.01);
assertTrue(Double.isNaN(IEEE754rUtils.max(Double.NaN, Double.NaN, Double.NaN)));
assertEquals(1.2f, IEEE754rUtils.min(1.2f, 2.5f, Float.NaN), 0.01);
assertEquals(2.5f, IEEE754rUtils.max(1.2f, 2.5f, Float.NaN), 0.01);
assertTrue(Float.isNaN(IEEE754rUtils.max(Float.NaN, Float.NaN, Float.NaN)));
double[] a = new double[] { 1.2, Double.NaN, 3.7, 27.0, 42.0, Double.NaN };
assertEquals(42.0, IEEE754rUtils.max(a), 0.01);
assertEquals(1.2, IEEE754rUtils.min(a), 0.01);
double[] b = new double[] { Double.NaN, 1.2, Double.NaN, 3.7, 27.0, 42.0, Double.NaN };
assertEquals(42.0, IEEE754rUtils.max(b), 0.01);
assertEquals(1.2, IEEE754rUtils.min(b), 0.01);
float[] aF = new float[] { 1.2f, Float.NaN, 3.7f, 27.0f, 42.0f, Float.NaN };
assertEquals(1.2f, IEEE754rUtils.min(aF), 0.01);
assertEquals(42.0f, IEEE754rUtils.max(aF), 0.01);
float[] bF = new float[] { Float.NaN, 1.2f, Float.NaN, 3.7f, 27.0f, 42.0f, Float.NaN };
assertEquals(1.2f, IEEE754rUtils.min(bF), 0.01);
assertEquals(42.0f, IEEE754rUtils.max(bF), 0.01);
}
}

View File

@ -1184,4 +1184,25 @@ public class NumberUtilsTest extends TestCase {
NumberUtils.createNumber("1l"); NumberUtils.createNumber("1l");
} }
public void testLang381() {
assertTrue(Double.isNaN(NumberUtils.min(1.2, 2.5, Double.NaN)));
assertTrue(Double.isNaN(NumberUtils.max(1.2, 2.5, Double.NaN)));
assertTrue(Float.isNaN(NumberUtils.min(1.2f, 2.5f, Float.NaN)));
assertTrue(Float.isNaN(NumberUtils.max(1.2f, 2.5f, Float.NaN)));
double[] a = new double[] { 1.2, Double.NaN, 3.7, 27.0, 42.0, Double.NaN };
assertTrue(Double.isNaN(NumberUtils.max(a)));
assertTrue(Double.isNaN(NumberUtils.min(a)));
double[] b = new double[] { Double.NaN, 1.2, Double.NaN, 3.7, 27.0, 42.0, Double.NaN };
assertTrue(Double.isNaN(NumberUtils.max(b)));
assertTrue(Double.isNaN(NumberUtils.min(b)));
float[] aF = new float[] { 1.2f, Float.NaN, 3.7f, 27.0f, 42.0f, Float.NaN };
assertTrue(Float.isNaN(NumberUtils.max(aF)));
float[] bF = new float[] { Float.NaN, 1.2f, Float.NaN, 3.7f, 27.0f, 42.0f, Float.NaN };
assertTrue(Float.isNaN(NumberUtils.max(bF)));
}
} }