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 Double
s 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 Double
s that
* compares for equality with the passed tolerance.
*
* @param tolerance the tolerance with which the returned Equality
will compare Double
s.
* @return an Equality
that compares Double
s 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 Float
s that
* compares for equality with the passed tolerance.
*
* @param tolerance the tolerance with which the returned Equality
will compare Float
s.
* @return an Equality
that compares Float
s 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 Long
s that
* compares for equality with the passed tolerance.
*
* @param tolerance the tolerance with which the returned Equality
will compare Long
s.
* @return an Equality
that compares Long
s 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 Int
s that
* compares for equality with the passed tolerance.
*
* @param tolerance the tolerance with which the returned Equality
will compare Int
s.
* @return an Equality
that compares Int
s 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 Short
s that
* compares for equality with the passed tolerance.
*
* @param tolerance the tolerance with which the returned Equality
will compare Short
s.
* @return an Equality
that compares Short
s 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 Byte
s that
* compares for equality with the passed tolerance.
*
* @param tolerance the tolerance with which the returned Equality
will compare Byte
s.
* @return an Equality
that compares Byte
s 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 N
s for equality with the passed tolerance.
*
* @param tolerance the tolerance with which the returned Equality
will compare Numeric
s.
* @return an Equivalence
that compares Numeric
s 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