| /* |
| * 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.numbers.complex; |
| |
| /** |
| * Utilities for comparing numbers. |
| */ |
| class Precision { |
| /** Offset to order signed double numbers lexicographically. */ |
| private static final long SGN_MASK = 0x8000000000000000L; |
| /** Positive zero bits. */ |
| private static final long POSITIVE_ZERO_DOUBLE_BITS = Double.doubleToRawLongBits(+0.0); |
| /** Negative zero bits. */ |
| private static final long NEGATIVE_ZERO_DOUBLE_BITS = Double.doubleToRawLongBits(-0.0); |
| |
| /** |
| * Private constructor. |
| */ |
| private Precision() {} |
| |
| /** |
| * Returns {@code true} if there is no double value strictly between the |
| * arguments or the difference between them is within the range of allowed |
| * error (inclusive). Returns {@code false} if either of the arguments |
| * is NaN. |
| * |
| * @param x First value. |
| * @param y Second value. |
| * @param eps Amount of allowed absolute error. |
| * @return {@code true} if the values are two adjacent floating point |
| * numbers or they are within range of each other. |
| */ |
| public static boolean equals(double x, double y, double eps) { |
| return equals(x, y, 1) || Math.abs(y - x) <= eps; |
| } |
| |
| /** |
| * Returns {@code true} if there is no double value strictly between the |
| * arguments or the relative difference between them is less than or equal |
| * to the given tolerance. Returns {@code false} if either of the arguments |
| * is NaN. |
| * |
| * @param x First value. |
| * @param y Second value. |
| * @param eps Amount of allowed relative error. |
| * @return {@code true} if the values are two adjacent floating point |
| * numbers or they are within range of each other. |
| */ |
| public static boolean equalsWithRelativeTolerance(double x, double y, double eps) { |
| if (equals(x, y, 1)) { |
| return true; |
| } |
| |
| final double absoluteMax = Math.max(Math.abs(x), Math.abs(y)); |
| final double relativeDifference = Math.abs((x - y) / absoluteMax); |
| |
| return relativeDifference <= eps; |
| } |
| |
| /** |
| * Returns true if the arguments are equal or within the range of allowed |
| * error (inclusive). |
| * <p> |
| * Two float numbers are considered equal if there are {@code (maxUlps - 1)} |
| * (or fewer) floating point numbers between them, i.e. two adjacent |
| * floating point numbers are considered equal. |
| * </p> |
| * <p> |
| * Adapted from <a |
| * href="http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/"> |
| * Bruce Dawson</a>. Returns {@code false} if either of the arguments is NaN. |
| * </p> |
| * |
| * @param x first value |
| * @param y second value |
| * @param maxUlps {@code (maxUlps - 1)} is the number of floating point |
| * values between {@code x} and {@code y}. |
| * @return {@code true} if there are fewer than {@code maxUlps} floating |
| * point values between {@code x} and {@code y}. |
| */ |
| public static boolean equals(final double x, final double y, final int maxUlps) { |
| |
| final long xInt = Double.doubleToRawLongBits(x); |
| final long yInt = Double.doubleToRawLongBits(y); |
| |
| final boolean isEqual; |
| if (((xInt ^ yInt) & SGN_MASK) == 0l) { |
| // number have same sign, there is no risk of overflow |
| isEqual = Math.abs(xInt - yInt) <= maxUlps; |
| } else { |
| // number have opposite signs, take care of overflow |
| final long deltaPlus; |
| final long deltaMinus; |
| if (xInt < yInt) { |
| deltaPlus = yInt - POSITIVE_ZERO_DOUBLE_BITS; |
| deltaMinus = xInt - NEGATIVE_ZERO_DOUBLE_BITS; |
| } else { |
| deltaPlus = xInt - POSITIVE_ZERO_DOUBLE_BITS; |
| deltaMinus = yInt - NEGATIVE_ZERO_DOUBLE_BITS; |
| } |
| |
| if (deltaPlus > maxUlps) { |
| isEqual = false; |
| } else { |
| isEqual = deltaMinus <= (maxUlps - deltaPlus); |
| } |
| |
| } |
| |
| return isEqual && !Double.isNaN(x) && !Double.isNaN(y); |
| |
| } |
| } |