Introduce inverse hyperbolic functions

#KT-4900

Improve accuracy of JS polyfills of hyperbolic functions and expm1/log1p
This commit is contained in:
Ilya Gorbunov
2017-08-30 21:00:30 +03:00
parent 232d1bd9ef
commit 044ccf1532
10 changed files with 634 additions and 29 deletions

View File

@@ -62,6 +62,12 @@ public external object Math {
internal fun cosh(value: Double): Double
@PublishedApi
internal fun tanh(value: Double): Double
@PublishedApi
internal fun asinh(value: Double): Double
@PublishedApi
internal fun acosh(value: Double): Double
@PublishedApi
internal fun atanh(value: Double): Double
@PublishedApi
internal fun hypot(x: Double, y: Double): Double

View File

@@ -152,6 +152,52 @@ public inline fun cosh(a: Double): Double = nativeMath.cosh(a)
@InlineOnly
public inline fun tanh(a: Double): Double = nativeMath.tanh(a)
/**
* Computes the inverse hyperbolic sine of the value [a].
*
* The returned value is `x` such that `sinh(x) == a`.
*
* Special cases:
*
* - `asinh(NaN)` is `NaN`
* - `asinh(+Inf)` is `+Inf`
* - `asinh(-Inf)` is `-Inf`
*/
@SinceKotlin("1.2")
@InlineOnly
public inline fun asinh(a: Double): Double = nativeMath.asinh(a)
/**
* Computes the inverse hyperbolic cosine of the value [a].
*
* The returned value is positive `x` such that `cosh(x) == a`.
*
* Special cases:
*
* - `acosh(NaN)` is `NaN`
* - `acosh(x)` is `NaN` when `x < 1`
* - `acosh(+Inf)` is `+Inf`
*/
@SinceKotlin("1.2")
@InlineOnly
public inline fun acosh(a: Double): Double = nativeMath.acosh(a)
/**
* Computes the inverse hyperbolic tangent of the value [a].
*
* The returned value is `x` such that `tanh(x) == a`.
*
* Special cases:
*
* - `tanh(NaN)` is `NaN`
* - `tanh(x)` is `NaN` when `x > 1` or `x < -1`
* - `tanh(1.0)` is `+Inf`
* - `tanh(-1.0)` is `-Inf`
*/
@SinceKotlin("1.2")
@InlineOnly
public inline fun atanh(a: Double): Double = nativeMath.atanh(a)
/**
* Computes `sqrt(x^2 + y^2)` without intermediate overflow or underflow.
*
@@ -592,6 +638,52 @@ public inline fun cosh(a: Float): Float = nativeMath.cosh(a.toDouble()).toFloat(
@InlineOnly
public inline fun tanh(a: Float): Float = nativeMath.tanh(a.toDouble()).toFloat()
/**
* Computes the inverse hyperbolic sine of the value [a].
*
* The returned value is `x` such that `sinh(x) == a`.
*
* Special cases:
*
* - `asinh(NaN)` is `NaN`
* - `asinh(+Inf)` is `+Inf`
* - `asinh(-Inf)` is `-Inf`
*/
@SinceKotlin("1.2")
@InlineOnly
public inline fun asinh(a: Float): Float = nativeMath.asinh(a.toDouble()).toFloat()
/**
* Computes the inverse hyperbolic cosine of the value [a].
*
* The returned value is positive `x` such that `cosh(x) == a`.
*
* Special cases:
*
* - `acosh(NaN)` is `NaN`
* - `acosh(x)` is `NaN` when `x < 1`
* - `acosh(+Inf)` is `+Inf`
*/
@SinceKotlin("1.2")
@InlineOnly
public inline fun acosh(a: Float): Float = nativeMath.acosh(a.toDouble()).toFloat()
/**
* Computes the inverse hyperbolic tangent of the value [a].
*
* The returned value is `x` such that `tanh(x) == a`.
*
* Special cases:
*
* - `tanh(NaN)` is `NaN`
* - `tanh(x)` is `NaN` when `x > 1` or `x < -1`
* - `tanh(1.0)` is `+Inf`
* - `tanh(-1.0)` is `-Inf`
*/
@SinceKotlin("1.2")
@InlineOnly
public inline fun atanh(a: Float): Float = nativeMath.atanh(a.toDouble()).toFloat()
/**
* Computes `sqrt(x^2 + y^2)` without intermediate overflow or underflow.
*

View File

@@ -52,24 +52,171 @@ if (typeof Math.trunc === "undefined") {
return Math.ceil(x);
};
}
if (typeof Math.sinh === "undefined") {
Math.sinh = function(x) {
var y = Math.exp(x);
return (y - 1 / y) / 2;
};
}
if (typeof Math.cosh === "undefined") {
Math.cosh = function(x) {
var y = Math.exp(x);
return (y + 1 / y) / 2;
};
}
if (typeof Math.tanh === "undefined") {
Math.tanh = function(x){
var a = Math.exp(+x), b = Math.exp(-x);
return a == Infinity ? 1 : b == Infinity ? -1 : (a - b) / (a + b);
};
}
(function() {
var epsilon = 2.220446049250313E-16;
var taylor_2_bound = Math.sqrt(epsilon);
var taylor_n_bound = Math.sqrt(taylor_2_bound);
var upper_taylor_2_bound = 1/taylor_2_bound;
var upper_taylor_n_bound = 1/taylor_n_bound;
if (typeof Math.sinh === "undefined") {
Math.sinh = function(x) {
if (Math.abs(x) < taylor_n_bound) {
var result = x;
if (Math.abs(x) > taylor_2_bound) {
result += (x * x * x) / 6;
}
return result;
} else {
var y = Math.exp(x);
var y1 = 1 / y;
if (!isFinite(y)) return Math.exp(x - Math.LN2);
if (!isFinite(y1)) return -Math.exp(-x - Math.LN2);
return (y - y1) / 2;
}
};
}
if (typeof Math.cosh === "undefined") {
Math.cosh = function(x) {
var y = Math.exp(x);
var y1 = 1 / y;
if (!isFinite(y) || !isFinite(y1)) return Math.exp(Math.abs(x) - Math.LN2);
return (y + y1) / 2;
};
}
if (typeof Math.tanh === "undefined") {
Math.tanh = function(x){
if (Math.abs(x) < taylor_n_bound) {
var result = x;
if (Math.abs(x) > taylor_2_bound) {
result -= (x * x * x) / 3;
}
return result;
}
else {
var a = Math.exp(+x), b = Math.exp(-x);
return a === Infinity ? 1 : b === Infinity ? -1 : (a - b) / (a + b);
}
};
}
// Inverse hyperbolic function implementations derived from boost special math functions,
// Copyright Eric Ford & Hubert Holin 2001.
if (typeof Math.asinh === "undefined") {
var asinh = function(x) {
if (x >= +taylor_n_bound)
{
if (x > upper_taylor_n_bound)
{
if (x > upper_taylor_2_bound)
{
// approximation by laurent series in 1/x at 0+ order from -1 to 0
return Math.log(x) + Math.LN2;
}
else
{
// approximation by laurent series in 1/x at 0+ order from -1 to 1
return Math.log(x * 2 + (1 / (x * 2)));
}
}
else
{
return Math.log(x + Math.sqrt(x * x + 1));
}
}
else if (x <= -taylor_n_bound)
{
return -asinh(-x);
}
else
{
// approximation by taylor series in x at 0 up to order 2
var result = x;
if (Math.abs(x) >= taylor_2_bound)
{
var x3 = x * x * x;
// approximation by taylor series in x at 0 up to order 4
result -= x3 / 6;
}
return result;
}
};
Math.asinh = asinh;
}
if (typeof Math.acosh === "undefined") {
Math.acosh = function(x) {
if (x < 1)
{
return NaN;
}
else if (x - 1 >= taylor_n_bound)
{
if (x > upper_taylor_2_bound)
{
// approximation by laurent series in 1/x at 0+ order from -1 to 0
return Math.log(x) + Math.LN2;
}
else
{
return Math.log(x + Math.sqrt(x * x - 1));
}
}
else
{
var y = Math.sqrt(x - 1);
// approximation by taylor series in y at 0 up to order 2
var result = y;
if (y >= taylor_2_bound)
{
var y3 = y * y * y;
// approximation by taylor series in y at 0 up to order 4
result -= y3 / 12;
}
return Math.sqrt(2) * result;
}
};
}
if (typeof Math.atanh === "undefined") {
Math.atanh = function(x) {
if (Math.abs(x) < taylor_n_bound) {
var result = x;
if (Math.abs(x) > taylor_2_bound) {
result += (x * x * x) / 3;
}
return result;
}
return Math.log((1 + x) / (1 - x)) / 2;
};
}
if (typeof Math.log1p === "undefined") {
Math.log1p = function(x) {
if (Math.abs(x) < taylor_n_bound) {
var x2 = x * x;
var x3 = x2 * x;
var x4 = x3 * x;
// approximation by taylor series in x at 0 up to order 4
return (-x4 / 4 + x3 / 3 - x2 / 2 + x);
}
return Math.log(x + 1);
};
}
if (typeof Math.expm1 === "undefined") {
Math.expm1 = function(x) {
if (Math.abs(x) < taylor_n_bound) {
var x2 = x * x;
var x3 = x2 * x;
var x4 = x3 * x;
// approximation by taylor series in x at 0 up to order 4
return (x4 / 24 + x3 / 6 + x2 / 2 + x);
}
return Math.exp(x) - 1;
};
}
})();
if (typeof Math.hypot === "undefined") {
Math.hypot = function() {
var y = 0;
@@ -94,16 +241,7 @@ if (typeof Math.log2 === "undefined") {
return Math.log(x) * Math.LOG2E;
};
}
if (typeof Math.log1p === "undefined") {
Math.log1p = function(x) {
return Math.log(x + 1);
};
}
if (typeof Math.expm1 === "undefined") {
Math.expm1 = function(x) {
return Math.exp(x) - 1;
};
}
// For HtmlUnit and PhantomJs
if (typeof ArrayBuffer.isView === "undefined") {
ArrayBuffer.isView = function(a) {

View File

@@ -140,6 +140,49 @@ public expect fun cosh(a: Double): Double
@SinceKotlin("1.2")
public expect fun tanh(a: Double): Double
/**
* Computes the inverse hyperbolic sine of the value [a].
*
* The returned value is `x` such that `sinh(x) == a`.
*
* Special cases:
*
* - `asinh(NaN)` is `NaN`
* - `asinh(+Inf)` is `+Inf`
* - `asinh(-Inf)` is `-Inf`
*/
@SinceKotlin("1.2")
public expect fun asinh(a: Double): Double
/**
* Computes the inverse hyperbolic cosine of the value [a].
*
* The returned value is positive `x` such that `cosh(x) == a`.
*
* Special cases:
*
* - `acosh(NaN)` is `NaN`
* - `acosh(x)` is `NaN` when `x < 1`
* - `acosh(+Inf)` is `+Inf`
*/
@SinceKotlin("1.2")
public expect fun acosh(a: Double): Double
/**
* Computes the inverse hyperbolic tangent of the value [a].
*
* The returned value is `x` such that `tanh(x) == a`.
*
* Special cases:
*
* - `tanh(NaN)` is `NaN`
* - `tanh(x)` is `NaN` when `x > 1` or `x < -1`
* - `tanh(1.0)` is `+Inf`
* - `tanh(-1.0)` is `-Inf`
*/
@SinceKotlin("1.2")
public expect fun atanh(a: Double): Double
/**
* Computes `sqrt(x^2 + y^2)` without intermediate overflow or underflow.
*
@@ -527,6 +570,49 @@ public expect fun cosh(a: Float): Float
@SinceKotlin("1.2")
public expect fun tanh(a: Float): Float
/**
* Computes the inverse hyperbolic sine of the value [a].
*
* The returned value is `x` such that `sinh(x) == a`.
*
* Special cases:
*
* - `asinh(NaN)` is `NaN`
* - `asinh(+Inf)` is `+Inf`
* - `asinh(-Inf)` is `-Inf`
*/
@SinceKotlin("1.2")
public expect fun asinh(a: Float): Float
/**
* Computes the inverse hyperbolic cosine of the value [a].
*
* The returned value is positive `x` such that `cosh(x) == a`.
*
* Special cases:
*
* - `acosh(NaN)` is `NaN`
* - `acosh(x)` is `NaN` when `x < 1`
* - `acosh(+Inf)` is `+Inf`
*/
@SinceKotlin("1.2")
public expect fun acosh(a: Float): Float
/**
* Computes the inverse hyperbolic tangent of the value [a].
*
* The returned value is `x` such that `tanh(x) == a`.
*
* Special cases:
*
* - `tanh(NaN)` is `NaN`
* - `tanh(x)` is `NaN` when `x > 1` or `x < -1`
* - `tanh(1.0)` is `+Inf`
* - `tanh(-1.0)` is `-Inf`
*/
@SinceKotlin("1.2")
public expect fun atanh(a: Float): Float
/**
* Computes `sqrt(x^2 + y^2)` without intermediate overflow or underflow.
*

View File

@@ -32,6 +32,12 @@ public const val E: Double = nativeMath.E
/** Natural logarithm of 2.0, used to compute [log2] function */
private val LN2: Double = ln(2.0)
private val epsilon: Double = nativeMath.ulp(1.0)
private val taylor_2_bound = nativeMath.sqrt(epsilon)
private val taylor_n_bound = nativeMath.sqrt(taylor_2_bound)
private val upper_taylor_2_bound = 1 / taylor_2_bound
private val upper_taylor_n_bound = 1 / taylor_n_bound
// ================ Double Math ========================================
/** Computes the sine of the angle [a] given in radians.
@@ -155,6 +161,109 @@ public inline fun cosh(a: Double): Double = nativeMath.cosh(a)
@InlineOnly
public inline fun tanh(a: Double): Double = nativeMath.tanh(a)
// Inverse hyperbolic function implementations derived from boost special math functions,
// Copyright Eric Ford & Hubert Holin 2001.
/**
* Computes the inverse hyperbolic sine of the value [a].
*
* The returned value is `x` such that `sinh(x) == a`.
*
* Special cases:
*
* - `asinh(NaN)` is `NaN`
* - `asinh(+Inf)` is `+Inf`
* - `asinh(-Inf)` is `-Inf`
*/
@SinceKotlin("1.2")
public fun asinh(a: Double): Double =
when {
a >= +taylor_n_bound ->
if (a > upper_taylor_n_bound) {
if (a > upper_taylor_2_bound) {
// approximation by laurent series in 1/x at 0+ order from -1 to 0
nativeMath.log(a) + LN2
} else {
// approximation by laurent series in 1/x at 0+ order from -1 to 1
nativeMath.log(a * 2 + (1 / (a * 2)))
}
} else {
nativeMath.log(a + nativeMath.sqrt(a * a + 1))
}
a <= -taylor_n_bound -> -asinh(-a)
else -> {
// approximation by taylor series in x at 0 up to order 2
var result = a;
if (nativeMath.abs(a) >= taylor_2_bound) {
// approximation by taylor series in x at 0 up to order 4
result -= (a * a * a) / 6
}
result
}
}
/**
* Computes the inverse hyperbolic cosine of the value [a].
*
* The returned value is positive `x` such that `cosh(x) == a`.
*
* Special cases:
*
* - `acosh(NaN)` is `NaN`
* - `acosh(x)` is `NaN` when `x < 1`
* - `acosh(+Inf)` is `+Inf`
*/
@SinceKotlin("1.2")
public fun acosh(a: Double): Double =
when {
a < 1 -> Double.NaN
a > upper_taylor_2_bound ->
// approximation by laurent series in 1/x at 0+ order from -1 to 0
nativeMath.log(a) + LN2
a - 1 >= taylor_n_bound ->
nativeMath.log(a + nativeMath.sqrt(a * a - 1))
else -> {
val y = nativeMath.sqrt(a - 1)
// approximation by taylor series in y at 0 up to order 2
var result = y
if (y >= taylor_2_bound) {
// approximation by taylor series in y at 0 up to order 4
result -= (y * y * y) / 12
}
nativeMath.sqrt(2.0) * result
}
}
/**
* Computes the inverse hyperbolic tangent of the value [a].
*
* The returned value is `x` such that `tanh(x) == a`.
*
* Special cases:
*
* - `tanh(NaN)` is `NaN`
* - `tanh(x)` is `NaN` when `x > 1` or `x < -1`
* - `tanh(1.0)` is `+Inf`
* - `tanh(-1.0)` is `-Inf`
*/
@SinceKotlin("1.2")
public fun atanh(x: Double): Double {
if (nativeMath.abs(x) < taylor_n_bound) {
var result = x
if (nativeMath.abs(x) > taylor_2_bound) {
result += (x * x * x) / 3
}
return result
}
return nativeMath.log((1 + x) / (1 - x)) / 2
}
/**
* Computes `sqrt(x^2 + y^2)` without intermediate overflow or underflow.
*
@@ -640,6 +749,52 @@ public inline fun cosh(a: Float): Float = nativeMath.cosh(a.toDouble()).toFloat(
@InlineOnly
public inline fun tanh(a: Float): Float = nativeMath.tanh(a.toDouble()).toFloat()
/**
* Computes the inverse hyperbolic sine of the value [a].
*
* The returned value is `x` such that `sinh(x) == a`.
*
* Special cases:
*
* - `asinh(NaN)` is `NaN`
* - `asinh(+Inf)` is `+Inf`
* - `asinh(-Inf)` is `-Inf`
*/
@SinceKotlin("1.2")
@InlineOnly
public inline fun asinh(a: Float): Float = asinh(a.toDouble()).toFloat()
/**
* Computes the inverse hyperbolic cosine of the value [a].
*
* The returned value is positive `x` such that `cosh(x) == a`.
*
* Special cases:
*
* - `acosh(NaN)` is `NaN`
* - `acosh(x)` is `NaN` when `x < 1`
* - `acosh(+Inf)` is `+Inf`
*/
@SinceKotlin("1.2")
@InlineOnly
public inline fun acosh(a: Float): Float = acosh(a.toDouble()).toFloat()
/**
* Computes the inverse hyperbolic tangent of the value [a].
*
* The returned value is `x` such that `tanh(x) == a`.
*
* Special cases:
*
* - `tanh(NaN)` is `NaN`
* - `tanh(x)` is `NaN` when `x > 1` or `x < -1`
* - `tanh(1.0)` is `+Inf`
* - `tanh(-1.0)` is `-Inf`
*/
@SinceKotlin("1.2")
@InlineOnly
public inline fun atanh(a: Float): Float = atanh(a.toDouble()).toFloat()
/**
* Computes `sqrt(x^2 + y^2)` without intermediate overflow or underflow.
*

View File

@@ -79,17 +79,60 @@ class DoubleMathTest {
@Test fun hyperbolic() {
assertEquals(Double.POSITIVE_INFINITY, sinh(Double.POSITIVE_INFINITY))
assertEquals(Double.NEGATIVE_INFINITY, sinh(Double.NEGATIVE_INFINITY))
assertTrue(sinh(Double.MIN_VALUE) != 0.0)
assertTrue(sinh(710.0).isFinite())
assertTrue(sinh(-710.0).isFinite())
assertTrue(sinh(Double.NaN).isNaN())
assertEquals(Double.POSITIVE_INFINITY, cosh(Double.POSITIVE_INFINITY))
assertEquals(Double.POSITIVE_INFINITY, cosh(Double.NEGATIVE_INFINITY))
assertTrue(cosh(710.0).isFinite())
assertTrue(cosh(-710.0).isFinite())
assertTrue(cosh(Double.NaN).isNaN())
assertAlmostEquals(1.0, tanh(Double.POSITIVE_INFINITY))
assertAlmostEquals(-1.0, tanh(Double.NEGATIVE_INFINITY))
assertTrue(tanh(Double.MIN_VALUE) != 0.0)
assertTrue(tanh(Double.NaN).isNaN())
}
@Test fun inverseHyperbolicSin() {
for (exact in listOf(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, 0.0, Double.MIN_VALUE, -Double.MIN_VALUE, 0.00001)) {
assertEquals(exact, asinh(sinh(exact)))
}
for (approx in listOf(Double.MIN_VALUE, 0.1, 1.0, 100.0, 710.0)) {
assertAlmostEquals(approx, asinh(sinh(approx)))
assertAlmostEquals(-approx, asinh(sinh(-approx)))
}
assertTrue(asinh(Double.NaN).isNaN())
}
@Test fun inverseHyperbolicCos() {
for (exact in listOf(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, 0.0)) {
assertEquals(abs(exact), acosh(cosh(exact)))
}
for (approx in listOf(Double.MIN_VALUE, 0.00001, 1.0, 100.0, 710.0)) {
assertAlmostEquals(approx, acosh(cosh(approx)))
assertAlmostEquals(approx, acosh(cosh(-approx)))
}
for (invalid in listOf(-1.0, 0.0, 0.99999, Double.NaN)) {
assertTrue(acosh(invalid).isNaN())
}
}
@Test fun inverseHyperbolicTan() {
for (exact in listOf(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, 0.0, Double.MIN_VALUE, -Double.MIN_VALUE)) {
assertEquals(exact, atanh(tanh(exact)))
}
for (approx in listOf(0.00001)) {
assertAlmostEquals(approx, atanh(tanh(approx)))
}
for (invalid in listOf(-1.00001, 1.00001, Double.NaN, Double.MAX_VALUE, -Double.MAX_VALUE, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY)) {
assertTrue(atanh(invalid).isNaN())
}
}
@Test fun powers() {
assertEquals(5.0, hypot(3.0, 4.0))
assertEquals(Double.POSITIVE_INFINITY, hypot(Double.NEGATIVE_INFINITY, Double.NaN))
@@ -117,6 +160,8 @@ class DoubleMathTest {
assertEquals(Double.POSITIVE_INFINITY, exp(Double.POSITIVE_INFINITY))
assertEquals(0.0, expm1(0.0))
assertEquals(Double.MIN_VALUE, expm1(Double.MIN_VALUE))
assertEquals(0.00010000500016667084, expm1(1e-4))
assertEquals(-1.0, expm1(Double.NEGATIVE_INFINITY))
assertEquals(Double.POSITIVE_INFINITY, expm1(Double.POSITIVE_INFINITY))
}
@@ -151,6 +196,8 @@ class DoubleMathTest {
assertTrue(ln1p(Double.NaN).isNaN())
assertTrue(ln1p(-1.1).isNaN())
assertEquals(0.0, ln1p(0.0))
assertEquals(9.999995000003334e-7, ln1p(1e-6))
assertEquals(Double.MIN_VALUE, ln1p(Double.MIN_VALUE))
assertEquals(Double.NEGATIVE_INFINITY, ln1p(-1.0))
}
@@ -323,17 +370,61 @@ class FloatMathTest {
@Test fun hyperbolic() {
assertEquals(Float.POSITIVE_INFINITY, sinh(Float.POSITIVE_INFINITY))
assertEquals(Float.NEGATIVE_INFINITY, sinh(Float.NEGATIVE_INFINITY))
assertTrue(sinh(Float.MIN_VALUE) != 0.0F)
assertTrue(sinh(89.0F).isFinite())
assertTrue(sinh(-89.0F).isFinite())
assertTrue(sinh(Float.NaN).isNaN())
assertEquals(Float.POSITIVE_INFINITY, cosh(Float.POSITIVE_INFINITY))
assertEquals(Float.POSITIVE_INFINITY, cosh(Float.NEGATIVE_INFINITY))
assertTrue(cosh(89.0F).isFinite())
assertTrue(cosh(-89.0F).isFinite())
assertTrue(cosh(Float.NaN).isNaN())
assertAlmostEquals(1.0F, tanh(Float.POSITIVE_INFINITY))
assertAlmostEquals(-1.0F, tanh(Float.NEGATIVE_INFINITY))
assertTrue(tanh(Float.MIN_VALUE) != 0.0F)
assertTrue(tanh(Float.NaN).isNaN())
}
@Test fun inverseHyperbolicSin() {
for (exact in listOf(Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY, 0.0F, Float.MIN_VALUE, -Float.MIN_VALUE, 0.00001F)) {
assertEquals(exact, asinh(sinh(exact)))
}
for (approx in listOf(Float.MIN_VALUE, 0.1F, 1.0F, 89.0F)) {
assertAlmostEquals(approx, asinh(sinh(approx)))
assertAlmostEquals(-approx, asinh(sinh(-approx)))
}
assertTrue(asinh(Float.NaN).isNaN())
}
@Test fun inverseHyperbolicCos() {
for (exact in listOf(Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY, 0.0F)) {
assertEquals(abs(exact), acosh(cosh(exact)))
}
for (approx in listOf(Float.MIN_VALUE, 0.1F, 1.0F, 89.0F)) {
assertAlmostEquals(approx, acosh(cosh(approx)))
assertAlmostEquals(approx, acosh(cosh(-approx)))
}
for (invalid in listOf(-1.0F, 0.0F, 0.99999F, Float.NaN)) {
assertTrue(acosh(invalid).isNaN())
}
}
@Test fun inverseHyperbolicTan() {
for (exact in listOf(Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY, 0.0F, Float.MIN_VALUE, -Float.MIN_VALUE)) {
assertEquals(exact, atanh(tanh(exact)))
}
for (approx in listOf(0.00001F)) {
assertAlmostEquals(approx, atanh(tanh(approx)))
}
for (invalid in listOf(-1.00001F, 1.00001F, Float.NaN, Float.MAX_VALUE, -Float.MAX_VALUE, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY)) {
assertTrue(atanh(invalid).isNaN())
}
}
@Test fun powers() {
assertEquals(5.0F, hypot(3.0F, 4.0F))
assertEquals(Float.POSITIVE_INFINITY, hypot(Float.NEGATIVE_INFINITY, Float.NaN))

View File

@@ -3016,6 +3016,9 @@ public abstract interface class kotlin/jvm/internal/markers/KMutableSet : kotlin
public final class kotlin/math/MathKt {
public static final field E D
public static final field PI D
public static final fun acosh (D)D
public static final fun asinh (D)D
public static final fun atanh (D)D
public static final fun getSign (I)I
public static final fun getSign (J)I
public static final fun log (DD)D

View File

@@ -2024,6 +2024,9 @@ public final class kotlin/io/TextStreamsKt {
public final class kotlin/math/MathKt {
public static final field E D
public static final field PI D
public static final fun acosh (D)D
public static final fun asinh (D)D
public static final fun atanh (D)D
public static final fun getSign (I)I
public static final fun getSign (J)I
public static final fun log (DD)D

View File

@@ -34,6 +34,10 @@ the Kotlin IntelliJ IDEA plugin:
- Path: js/js.libraries/src/js/long.js
- License: Apache 2 (license/third_party/closure-compiler_LICENSE.txt)
- Origin: Google Closure Library, Copyright 2009 The Closure Library Authors
- Path: js/js.libraries/src/js/polyfills.js
- License: Boost Software License 1.0 (license/third_party/boost_LICENSE.txt)
- Origin: Derived from boost special math functions, Copyright Eric Ford & Hubert Holin 2001.
- Path: js/js.parser/src/com/google
- License: Netscape Public License 1.1 (license/third_party/rhino_LICENSE.txt)
@@ -48,7 +52,11 @@ the Kotlin IntelliJ IDEA plugin:
- Path: libraries/stdlib/src/kotlin/collections
- License: Apache 2 (license/third_party/gwt_license.txt)
- Origin: Derived from GWT, (C) 2007-08 Google Inc.
- Path: libraries/stdlib/src/kotlin/util/MathJVM.kt
- License: Boost Software License 1.0 (license/third_party/boost_LICENSE.txt)
- Origin: Derived from boost special math functions, Copyright Eric Ford & Hubert Holin 2001.
- Path: plugins/lint/android-annotations
- License: Apache 2 (license/third_party/aosp_license.txt)
- Origin: Copyright (C) 2011-15 The Android Open Source Project

23
license/third_party/boost_LICENSE.txt vendored Normal file
View File

@@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.