All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.scalactic.TolerantNumerics.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2001-2013 Artima, Inc.
 *
 * 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 org.scalactic

/*
 * Defines a custom way to determine equality for a type.
 *
 * 

* For example, here's how you could define equality between Doubles such that * a tolerance of ± 0.01 is allowed: *

* *
 * class TolerantDoubleEquality extends Equality[Double] {
 *
 *   private val Tol = 0.01
 *
 *   def areEqual(a: Double, b: Any): Boolean = {
 *     b match {
 *       case bDouble: Double => (a <= bDouble + Tol) && (a >= bDouble - Tol)
 *       case _ => false
 *     }
 *   }
 * }
 * 
* *

* If an implicit instance of TolerantDoubleEquality is in scope, it will be * used by ScalaTest's === operators and its should equal and should === matcher * syntax. Here's an example: *

* *
 * $ scala -cp target/jar_contents/
 * Welcome to Scala version 2.10.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_33).
 * Type in expressions to have them evaluated.
 * Type :help for more information.

 * scala> import org.scalactic._
 * import org.scalactic._

 * scala> class TolerantDoubleEquality extends Equality[Double] {
 *      | 
 *      |   private val Tol = 0.01
 *      | 
 *      |   def areEqual(a: Double, b: Any): Boolean = {
 *      |     b match {
 *      |       case bDouble: Double => (a >= bDouble + Tol) && (a >= bDouble - Tol)
 *      |       case _ => false
 *      |     }
 *      |   }
 *      | }
 * defined class TolerantDoubleEquality
 *
 * scala> import TripleEquals._
 * import TripleEquals._
 *
 * scala> 2.0 === 2.001
 * res0: Boolean = false
 *
 * scala> implicit val tolerantDoubleEquality = new TolerantDoubleEquality
 * tolerantDoubleEquality: TolerantDoubleEquality = TolerantDoubleEquality@70c13c17
 *
 * scala> 2.0 === 2.001
 * res1: Boolean = true
 * 
* *

* Note: The Equality type class was inspired in part by the Equal type class of the * scalaz project. *

* * @tparam A the type whose equality is being customized */ /** * Provides Equality and Equivalence instances for Numeric types that * compare for equality with a given tolerance. * *

Here's an example:

* *
 * scala> import org.scalactic._
 * import org.scalactic._
 *
 * scala> import TripleEquals._
 * import TripleEquals._
 *
 * scala> 2.001 === 2.0
 * res0: Boolean = false
 *
 * scala> implicit val doubleEquality = TolerantNumerics.tolerantDoubleEquality(0.01)
 * doubleEquality: org.scalactic.Equality[Double] = org.scalactic.TolerantNumerics$$anon$1@16c2bd13
 *
 * scala> 2.001 === 2.0
 * res1: Boolean = true
 * 
*/ trait TolerantNumerics { // TODO: Pretty toStrings on the results /** * Provides an Equality instance for Doubles that * compares for equality with the passed tolerance. * * @param tolerance the tolerance with which the returned Equality will compare Doubles. * @return an Equality that compares Doubles using the passed tolerance. */ def tolerantDoubleEquality(tolerance: Double): Equality[Double] = { if (tolerance <= 0.0) throw new IllegalArgumentException(tolerance.toString + " passed to tolerantDoubleEquality was zero or negative. Must be a positive non-zero number.") new Equality[Double] { def areEqual(a: Double, b: Any): Boolean = { b match { case bDouble: Double => (a <= bDouble + tolerance) && (a >= bDouble - tolerance) case _ => false } } override def toString: String = s"TolerantDoubleEquality($tolerance)" } } /** * Provides an Equality instance for Floats that * compares for equality with the passed tolerance. * * @param tolerance the tolerance with which the returned Equality will compare Floats. * @return an Equality that compares Floats using the passed tolerance. */ def tolerantFloatEquality(tolerance: Float): Equality[Float] = { if (tolerance <= 0.0f) throw new IllegalArgumentException(tolerance.toString + " passed to tolerantFloatEquality was zero or negative. Must be a positive non-zero number.") new Equality[Float] { def areEqual(a: Float, b: Any): Boolean = { b match { case bFloat: Float => (a <= bFloat + tolerance) && (a >= bFloat - tolerance) case _ => false } } override def toString: String = s"TolerantFloatEquality($tolerance)" } } /** * Provides an Equality instance for Longs that * compares for equality with the passed tolerance. * * @param tolerance the tolerance with which the returned Equality will compare Longs. * @return an Equality that compares Longs using the passed tolerance. */ def tolerantLongEquality(tolerance: Long): Equality[Long] = { if (tolerance <= 0L) throw new IllegalArgumentException(tolerance.toString + " passed to tolerantLongEquality was zero or negative. Must be a positive non-zero number.") new Equality[Long] { def areEqual(a: Long, b: Any): Boolean = { b match { case bLong: Long => (a <= bLong + tolerance) && (a >= bLong - tolerance) case _ => false } } override def toString: String = s"TolerantLongEquality($tolerance)" } } /** * Provides an Equality instance for Ints that * compares for equality with the passed tolerance. * * @param tolerance the tolerance with which the returned Equality will compare Ints. * @return an Equality that compares Ints using the passed tolerance. */ def tolerantIntEquality(tolerance: Int): Equality[Int] = { if (tolerance <= 0) throw new IllegalArgumentException(tolerance.toString + " passed to tolerantIntEquality was zero or negative. Must be a positive non-zero number.") new Equality[Int] { def areEqual(a: Int, b: Any): Boolean = { b match { case bInt: Int => (a <= bInt + tolerance) && (a >= bInt - tolerance) case _ => false } } override def toString: String = s"TolerantIntEquality($tolerance)" } } /** * Provides an Equality instance for Shorts that * compares for equality with the passed tolerance. * * @param tolerance the tolerance with which the returned Equality will compare Shorts. * @return an Equality that compares Shorts using the passed tolerance. */ def tolerantShortEquality(tolerance: Short): Equality[Short] = { if (tolerance <= 0) throw new IllegalArgumentException(tolerance.toString + " passed to tolerantShortEquality was zero or negative. Must be a positive non-zero number.") new Equality[Short] { def areEqual(a: Short, b: Any): Boolean = { b match { case bShort: Short => (a <= bShort + tolerance) && (a >= bShort - tolerance) case _ => false } } override def toString: String = s"TolerantShortEquality($tolerance)" } } /** * Provides an Equality instance for Bytes that * compares for equality with the passed tolerance. * * @param tolerance the tolerance with which the returned Equality will compare Bytes. * @return an Equality that compares Bytes using the passed tolerance. */ def tolerantByteEquality(tolerance: Byte): Equality[Byte] = { if (tolerance <= 0) throw new IllegalArgumentException(tolerance.toString + " passed to tolerantByteEquality was zero or negative. Must be a positive non-zero number.") new Equality[Byte] { def areEqual(a: Byte, b: Any): Boolean = { b match { case bByte: Byte => (a <= bByte + tolerance) && (a >= bByte - tolerance) case _ => false } } override def toString: String = s"TolerantByteEquality($tolerance)" } } /** * Provides an Equivalence[N] instance for any type for which a Numeric[N] is available that * compares Ns for equality with the passed tolerance. * * @param tolerance the tolerance with which the returned Equality will compare Numerics. * @return an Equivalence that compares Numerics using the passed tolerance. */ def tolerantEquivalence[N : Numeric](tolerance: N): Equivalence[N] = { val numeric = implicitly[Numeric[N]] if (numeric.lt(tolerance, numeric.zero)) throw new IllegalArgumentException(tolerance.toString + " passed to tolerantEquivalence was zero or negative. Must be a positive non-zero number.") new Equivalence[N] { def areEquivalent(a: N, b: N): Boolean = { val bPlusTolerance = numeric.plus(b, tolerance) val bMinusTolerance = numeric.minus(b, tolerance) (numeric.lteq(a, bPlusTolerance)) && (numeric.gteq(a, bMinusTolerance)) } override def toString: String = s"TolerantEquivalence($tolerance)" } } } /** * Companion object for TolerantNumerics that enables its members to be imported as an alternative to * mixing them in. */ object TolerantNumerics extends TolerantNumerics




© 2015 - 2024 Weber Informatics LLC | Privacy Policy