From 7889d13974eb0f4260eac5265b313dbf519ec90e Mon Sep 17 00:00:00 2001 From: Ilya Matveev Date: Tue, 21 Nov 2017 11:39:11 +0700 Subject: [PATCH] stdlib: Support kotlin.math --- licenses/third_party/boost_LICENSE.txt | 23 + runtime/src/main/cpp/Exceptions.h | 2 + runtime/src/main/cpp/Math.cpp | 358 +++++ .../kotlin/konan/internal/RuntimeUtils.kt | 5 + runtime/src/main/kotlin/kotlin/Numbers.kt | 6 +- runtime/src/main/kotlin/kotlin/math/math.kt | 1221 +++++++++++++++++ 6 files changed, 1613 insertions(+), 2 deletions(-) create mode 100644 licenses/third_party/boost_LICENSE.txt create mode 100644 runtime/src/main/cpp/Math.cpp create mode 100644 runtime/src/main/kotlin/kotlin/math/math.kt diff --git a/licenses/third_party/boost_LICENSE.txt b/licenses/third_party/boost_LICENSE.txt new file mode 100644 index 00000000000..127a5bc39ba --- /dev/null +++ b/licenses/third_party/boost_LICENSE.txt @@ -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. \ No newline at end of file diff --git a/runtime/src/main/cpp/Exceptions.h b/runtime/src/main/cpp/Exceptions.h index 8ed2a5f71dc..9f3b106b4ff 100644 --- a/runtime/src/main/cpp/Exceptions.h +++ b/runtime/src/main/cpp/Exceptions.h @@ -46,6 +46,8 @@ void ThrowArithmeticException(); void ThrowNumberFormatException(); // Throws out of memory error. void ThrowOutOfMemoryError(); +// Throws not implemented error. +void ThrowNotImplementedError(); // Prints out mesage of Throwable. void PrintThrowable(KRef); diff --git a/runtime/src/main/cpp/Math.cpp b/runtime/src/main/cpp/Math.cpp new file mode 100644 index 00000000000..d53f1ea1a05 --- /dev/null +++ b/runtime/src/main/cpp/Math.cpp @@ -0,0 +1,358 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * 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. + */ + +#include +#include +#include + +#include "Exceptions.h" +#include "Types.h" + +#if (__MINGW32__ || __MINGW64__) +#define KONAN_NEED_ASINH_ACOSH 1 +#else +#define KONAN_NEED_ASINH_ACOSH 0 +#endif + +#ifdef KONAN_WASM +#define KONAN_NO_MATH 1 +#else +#define KONAN_NO_MATH 0 +#endif + + +#ifdef KONAN_NEED_ASINH_ACOSH +namespace { + + // MinGW's implmenetation if asinh/acosh function returns NaN for large arguments so we use another implementation. + // Both implementations derived from boost special math functions and are also used by Kotlin/JVM. + // Copyright Eric Ford & Hubert Holin 2001. + + constexpr KDouble LN2 = 0.69314718055994530942; + constexpr KDouble SQRT2 = 1.41421356237309504880; + + KDouble taylor_2_bound = sqrt(DBL_EPSILON); + KDouble taylor_n_bound = sqrt(taylor_2_bound); + KDouble upper_taylor_2_bound = 1.0 / taylor_2_bound; + KDouble upper_taylor_n_bound = 1.0 / taylor_n_bound; + + KDouble custom_asinh(KDouble 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 log(x) + LN2; + } else { + // approximation by laurent series in 1/x at 0+ order from -1 to 1 + return log(x * 2 + (1.0 / (x * 2))); + } + } else { + return log(x + sqrt(x * x + 1)); + } + } else if (x <= -taylor_n_bound) { + return -custom_asinh(-x); + } else { + // approximation by taylor series in x at 0 up to order 2 + KDouble result = x; + if (fabs(x) >= taylor_2_bound) { + // approximation by taylor series in x at 0 up to order 4 + result -= (x * x * x) / 6; + } + return result; + } + } + + KDouble custom_acosh(KDouble x) { + if (x < 1) { + return NAN; + } else if (x > upper_taylor_2_bound) { + // approximation by laurent series in 1/x at 0+ order from -1 to 0 + return log(x) + LN2; + } else if (x - 1 >= taylor_n_bound) { + return log(x + sqrt(x * x - 1)); + } else { + KDouble y = sqrt(x - 1); + // approximation by taylor series in y at 0 up to order 2 + KDouble result = y; + if (y >= taylor_2_bound) { + // approximation by taylor series in y at 0 up to order 4 + result -= (y * y * y) / 12; + } + return SQRT2 * result; + } + } +} +#endif + +extern "C" { + +#if !KONAN_NO_MATH // There is a platform math library. + +// region Double math. + +KDouble Kotlin_math_sin(KDouble x) { return sin(x); } +KDouble Kotlin_math_cos(KDouble x) { return cos(x); } +KDouble Kotlin_math_tan(KDouble x) { return tan(x); } +KDouble Kotlin_math_asin(KDouble x) { return asin(x); } +KDouble Kotlin_math_acos(KDouble x) { return acos(x); } +KDouble Kotlin_math_atan(KDouble x) { return atan(x); } +KDouble Kotlin_math_atan2(KDouble y, KDouble x) { return atan2(y, x); } + +KDouble Kotlin_math_sinh(KDouble x) { return sinh(x); } +KDouble Kotlin_math_cosh(KDouble x) { return cosh(x); } +KDouble Kotlin_math_tanh(KDouble x) { return tanh(x); } + +KDouble Kotlin_math_asinh(KDouble x) { +#if (KONAN_NEED_ASINH_ACOSH) + return custom_asinh(x); +#else + return asinh(x); +#endif +} + +KDouble Kotlin_math_acosh(KDouble x) { +#if (KONAN_NEED_ASINH_ACOSH) + return custom_acosh(x); +#else + return acosh(x); +#endif +} + +KDouble Kotlin_math_atanh(KDouble x) { return atanh(x); } + +KDouble Kotlin_math_hypot(KDouble x, KDouble y) { return hypot(x, y); } +KDouble Kotlin_math_sqrt(KDouble x) { return sqrt(x); } +KDouble Kotlin_math_exp(KDouble x) { return exp(x); } +KDouble Kotlin_math_expm1(KDouble x) { return expm1(x); } + +KDouble Kotlin_math_ln(KDouble x) { return log(x); } +KDouble Kotlin_math_log10(KDouble x) { return log10(x); } +KDouble Kotlin_math_log2(KDouble x) { return log2(x); } +KDouble Kotlin_math_ln1p(KDouble x) { return log1p(x); } + +KDouble Kotlin_math_ceil(KDouble x) { return ceil(x); } +KDouble Kotlin_math_floor(KDouble x) { return floor(x); } +KDouble Kotlin_math_round(KDouble x) { return rint(x); } + +KDouble Kotlin_math_abs(KDouble x) { return fabs(x); } + +// extensions + +KDouble Kotlin_math_Double_pow(KDouble thiz, KDouble x) { + if (isinf(x) && (thiz == 1.0 || thiz == -1.0)) return NAN; // Kotlin corner case + return pow(thiz, x); +} + +KDouble Kotlin_math_Double_IEEErem(KDouble thiz, KDouble divisor) { return remainder(thiz, divisor); } +KDouble Kotlin_math_Double_withSign(KDouble thiz, KDouble sign) { return copysign(thiz, sign); } + +KDouble Kotlin_math_Double_nextUp(KDouble thiz) { return nextafter(thiz, HUGE_VAL); } +KDouble Kotlin_math_Double_nextDown(KDouble thiz) { return nextafter(thiz, -HUGE_VAL); } +KDouble Kotlin_math_Double_nextTowards(KDouble thiz, KDouble to) { + return (thiz == to) ? to : nextafter(thiz, to); +} + +KBoolean Kotlin_math_Double_signBit(KDouble thiz) { return signbit(thiz) != 0; } + +// endregion + +// region Float math. + +KFloat Kotlin_math_sinf(KFloat x) { return sinf(x); } +KFloat Kotlin_math_cosf(KFloat x) { return cosf(x); } +KFloat Kotlin_math_tanf(KFloat x) { return tanf(x); } +KFloat Kotlin_math_asinf(KFloat x) { return asinf(x); } +KFloat Kotlin_math_acosf(KFloat x) { return acosf(x); } +KFloat Kotlin_math_atanf(KFloat x) { return atanf(x); } +KFloat Kotlin_math_atan2f(KFloat y, KFloat x) { return atan2f(y, x); } + +KFloat Kotlin_math_sinhf(KFloat x) { return sinhf(x); } +KFloat Kotlin_math_coshf(KFloat x) { return coshf(x); } +KFloat Kotlin_math_tanhf(KFloat x) { return tanhf(x); } + +KFloat Kotlin_math_asinhf(KFloat x) { +#if (KONAN_NEED_ASINH_ACOSH) + return (KFloat)custom_asinh((KDouble)x); +#else + return asinhf(x); +#endif +} + +KFloat Kotlin_math_acoshf(KFloat x) { +#if (KONAN_NEED_ASINH_ACOSH) + return (KFloat)custom_acosh((KDouble)x); +#else + return acoshf(x); +#endif +} + +KFloat Kotlin_math_atanhf(KFloat x) { return atanhf(x); } + +KFloat Kotlin_math_hypotf(KFloat x, KFloat y) { return hypotf(x, y); } +KFloat Kotlin_math_sqrtf(KFloat x) { return sqrtf(x); } +KFloat Kotlin_math_expf(KFloat x) { return expf(x); } +KFloat Kotlin_math_expm1f(KFloat x) { return expm1f(x); } + +KFloat Kotlin_math_lnf(KFloat x) { return logf(x); } +KFloat Kotlin_math_log10f(KFloat x) { return log10f(x); } +KFloat Kotlin_math_log2f(KFloat x) { return log2f(x); } +KFloat Kotlin_math_ln1pf(KFloat x) { return log1pf(x); } + +KFloat Kotlin_math_ceilf(KFloat x) { return ceilf(x); } +KFloat Kotlin_math_floorf(KFloat x) { return floorf(x); } +KFloat Kotlin_math_roundf(KFloat x) { return rintf(x); } + +KFloat Kotlin_math_absf(KFloat x) { return fabsf(x); } + +// extensions + +KFloat Kotlin_math_Float_pow(KFloat thiz, KFloat x) { + if (isinf(x) && (thiz == 1.0 || thiz == -1.0)) return NAN; // Kotlin corner case + return powf(thiz, x); +} + +KFloat Kotlin_math_Float_IEEErem(KFloat thiz, KFloat divisor) { return remainderf(thiz, divisor); } +KFloat Kotlin_math_Float_withSign(KFloat thiz, KFloat sign) { return copysignf(thiz, sign); } + +KFloat Kotlin_math_Float_nextUp(KFloat thiz) { return nextafterf(thiz, HUGE_VALF); } +KFloat Kotlin_math_Float_nextDown(KFloat thiz) { return nextafterf(thiz, -HUGE_VALF); } +KFloat Kotlin_math_Float_nextTowards(KFloat thiz, KFloat to) { + return (thiz == to) ? to : nextafterf(thiz, to); +} + +KBoolean Kotlin_math_Float_signBit(KFloat thiz) { return signbit(thiz) != 0; } + +// endregion + +// region Integer math. + +KInt Kotlin_math_absi(KInt x) { return labs(x); } +KLong Kotlin_math_absl(KLong x) { return llabs(x); } + +// endregion + +#else // if there is no platform math library. + +// kotlin.math isn't supported for WASM. +namespace { + void NotImplemented() { ThrowNotImplementedError(); } +} + +KDouble Kotlin_math_sin(KDouble x) { NotImplemented(); } +KDouble Kotlin_math_cos(KDouble x) { NotImplemented(); } +KDouble Kotlin_math_tan(KDouble x) { NotImplemented(); } +KDouble Kotlin_math_asin(KDouble x) { NotImplemented(); } +KDouble Kotlin_math_acos(KDouble x) { NotImplemented(); } +KDouble Kotlin_math_atan(KDouble x) { NotImplemented(); } +KDouble Kotlin_math_atan2(KDouble y, KDouble x) { NotImplemented(); } + +KDouble Kotlin_math_sinh(KDouble x) { NotImplemented(); } +KDouble Kotlin_math_cosh(KDouble x) { NotImplemented(); } +KDouble Kotlin_math_tanh(KDouble x) { NotImplemented(); } +KDouble Kotlin_math_asinh(KDouble x) { NotImplemented(); } +KDouble Kotlin_math_acosh(KDouble x) { NotImplemented(); } +KDouble Kotlin_math_atanh(KDouble x) { NotImplemented(); } + +KDouble Kotlin_math_hypot(KDouble x, KDouble y) { NotImplemented(); } +KDouble Kotlin_math_sqrt(KDouble x) { NotImplemented(); } +KDouble Kotlin_math_exp(KDouble x) { NotImplemented(); } +KDouble Kotlin_math_expm1(KDouble x) { NotImplemented(); } + +KDouble Kotlin_math_ln(KDouble x) { NotImplemented(); } +KDouble Kotlin_math_log10(KDouble x) { NotImplemented(); } +KDouble Kotlin_math_log2(KDouble x) { NotImplemented(); } +KDouble Kotlin_math_ln1p(KDouble x) { NotImplemented(); } + +KDouble Kotlin_math_ceil(KDouble x) { NotImplemented(); } +KDouble Kotlin_math_floor(KDouble x) { NotImplemented(); } +KDouble Kotlin_math_round(KDouble x) { NotImplemented(); } + +KDouble Kotlin_math_abs(KDouble x) { NotImplemented(); } + +// extensions + +KDouble Kotlin_math_Double_pow(KDouble thiz, KDouble x) { NotImplemented(); } +KDouble Kotlin_math_Double_IEEErem(KDouble thiz, KDouble divisor) { NotImplemented(); } +KDouble Kotlin_math_Double_withSign(KDouble thiz, KDouble sign) { NotImplemented(); } + +KDouble Kotlin_math_Double_nextUp(KDouble thiz) { NotImplemented(); } +KDouble Kotlin_math_Double_nextDown(KDouble thiz) { NotImplemented(); } +KDouble Kotlin_math_Double_nextTowards(KDouble thiz, KDouble to) { NotImplemented(); } + +KBoolean Kotlin_math_Double_signBit(KDouble thiz) { NotImplemented(); } + +// endregion + +// region Float math. + +KFloat Kotlin_math_sinf(KFloat x) { NotImplemented(); } +KFloat Kotlin_math_cosf(KFloat x) { NotImplemented(); } +KFloat Kotlin_math_tanf(KFloat x) { NotImplemented(); } +KFloat Kotlin_math_asinf(KFloat x) { NotImplemented(); } +KFloat Kotlin_math_acosf(KFloat x) { NotImplemented(); } +KFloat Kotlin_math_atanf(KFloat x) { NotImplemented(); } +KFloat Kotlin_math_atan2f(KFloat y, KFloat x) { NotImplemented(); } + +KFloat Kotlin_math_sinhf(KFloat x) { NotImplemented(); } +KFloat Kotlin_math_coshf(KFloat x) { NotImplemented(); } +KFloat Kotlin_math_tanhf(KFloat x) { NotImplemented(); } +KFloat Kotlin_math_asinhf(KFloat x) { NotImplemented(); } +KFloat Kotlin_math_acoshf(KFloat x) { NotImplemented(); } +KFloat Kotlin_math_atanhf(KFloat x) { NotImplemented(); } + +KFloat Kotlin_math_hypotf(KFloat x, KFloat y) { NotImplemented(); } +KFloat Kotlin_math_sqrtf(KFloat x) { NotImplemented(); } +KFloat Kotlin_math_expf(KFloat x) { NotImplemented(); } +KFloat Kotlin_math_expm1f(KFloat x) { NotImplemented(); } + +KFloat Kotlin_math_lnf(KFloat x) { NotImplemented(); } +KFloat Kotlin_math_log10f(KFloat x) { NotImplemented(); } +KFloat Kotlin_math_log2f(KFloat x) { NotImplemented(); } +KFloat Kotlin_math_ln1pf(KFloat x) { NotImplemented(); } + +KFloat Kotlin_math_ceilf(KFloat x) { NotImplemented(); } +KFloat Kotlin_math_floorf(KFloat x) { NotImplemented(); } +KFloat Kotlin_math_roundf(KFloat x) { NotImplemented(); } + +KFloat Kotlin_math_absf(KFloat x) { NotImplemented(); } + +// extensions + +KFloat Kotlin_math_Float_pow(KFloat thiz, KFloat x) { NotImplemented(); } +KFloat Kotlin_math_Float_IEEErem(KFloat thiz, KFloat divisor) { NotImplemented(); } +KFloat Kotlin_math_Float_withSign(KFloat thiz, KFloat sign) { NotImplemented(); } + +KFloat Kotlin_math_Float_nextUp(KFloat thiz) { NotImplemented(); } +KFloat Kotlin_math_Float_nextDown(KFloat thiz) { NotImplemented(); } +KFloat Kotlin_math_Float_nextTowards(KFloat thiz, KFloat to) { NotImplemented(); } + +KBoolean Kotlin_math_Float_signBit(KFloat thiz) { NotImplemented(); } + +// endregion + +// region Integer math + +KInt Kotlin_math_absi(KInt x) { NotImplemented(); } +KInt Kotlin_math_mini(KInt a, KInt b) { NotImplemented(); } +KInt Kotlin_math_maxi(KInt a, KInt b) { NotImplemented(); } + +KLong Kotlin_math_absl(KLong x) { NotImplemented(); } +KLong Kotlin_math_minl(KLong a, KLong b) { NotImplemented(); } +KLong Kotlin_math_maxl(KLong a, KLong b) { NotImplemented(); } + +#endif // #if !KONAN_NO_MATH + +} // extern "C" diff --git a/runtime/src/main/kotlin/konan/internal/RuntimeUtils.kt b/runtime/src/main/kotlin/konan/internal/RuntimeUtils.kt index 7c9d634c963..76acdd979f5 100644 --- a/runtime/src/main/kotlin/konan/internal/RuntimeUtils.kt +++ b/runtime/src/main/kotlin/konan/internal/RuntimeUtils.kt @@ -61,6 +61,11 @@ fun ThrowUninitializedPropertyAccessException(): Nothing { throw UninitializedPropertyAccessException() } +@ExportForCppRuntime +internal fun ThrowNotImplementedError(): Nothing { + throw NotImplementedError("An operation is not implemented.") +} + @ExportForCppRuntime fun PrintThrowable(throwable: Throwable) { println(throwable) diff --git a/runtime/src/main/kotlin/kotlin/Numbers.kt b/runtime/src/main/kotlin/kotlin/Numbers.kt index 84214f7286c..006b813dd61 100644 --- a/runtime/src/main/kotlin/kotlin/Numbers.kt +++ b/runtime/src/main/kotlin/kotlin/Numbers.kt @@ -68,7 +68,8 @@ public inline fun Double.toBits(): Long = if (isNaN()) Double.NaN.toRawBits() el * preserving `NaN` values exact layout. */ @SinceKotlin("1.2") -public fun Double.toRawBits(): Long = bits() +@kotlin.internal.InlineOnly +public inline fun Double.toRawBits(): Long = bits() /** * Returns the [Double] value corresponding to a given bit representation. @@ -95,7 +96,8 @@ public inline fun Float.toBits(): Int = if (isNaN()) Float.NaN.toRawBits() else * preserving `NaN` values exact layout. */ @SinceKotlin("1.2") -public fun Float.toRawBits(): Int = bits() +@kotlin.internal.InlineOnly +public inline fun Float.toRawBits(): Int = bits() /** * Returns the [Float] value corresponding to a given bit representation. diff --git a/runtime/src/main/kotlin/kotlin/math/math.kt b/runtime/src/main/kotlin/kotlin/math/math.kt new file mode 100644 index 00000000000..875f18d3785 --- /dev/null +++ b/runtime/src/main/kotlin/kotlin/math/math.kt @@ -0,0 +1,1221 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * 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 kotlin.math + +// region ================ Constants ======================================== + +/** Ratio of the circumference of a circle to its diameter, approximately 3.14159. */ +@SinceKotlin("1.2") +public const val PI: Double = 3.141592653589793 +/** Base of the natural logarithms, approximately 2.71828. */ +@SinceKotlin("1.2") +public const val E: Double = 2.718281828459045 + +// endregion + +// region ================ Double Math ======================================== + +/** Computes the sine of the angle [x] given in radians. + * + * Special cases: + * - `sin(NaN|+Inf|-Inf)` is `NaN` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_sin") +external public fun sin(x: Double): Double + +/** Computes the cosine of the angle [x] given in radians. + * + * Special cases: + * - `cos(NaN|+Inf|-Inf)` is `NaN` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_cos") +external public fun cos(x: Double): Double + +/** Computes the tangent of the angle [x] given in radians. + * + * Special cases: + * - `tan(NaN|+Inf|-Inf)` is `NaN` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_tan") +external public fun tan(x: Double): Double + +/** + * Computes the arc sine of the value [x]; + * the returned value is an angle in the range from `-PI/2` to `PI/2` radians. + * + * Special cases: + * - `asin(x)` is `NaN`, when `abs(x) > 1` or x is `NaN` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_asin") +external public fun asin(x: Double): Double + +/** + * Computes the arc cosine of the value [x]; + * the returned value is an angle in the range from `0.0` to `PI` radians. + * + * Special cases: + * - `acos(x)` is `NaN`, when `abs(x) > 1` or x is `NaN` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_acos") +external public fun acos(x: Double): Double + +/** + * Computes the arc tangent of the value [x]; + * the returned value is an angle in the range from `-PI/2` to `PI/2` radians. + * + * Special cases: + * - `atan(NaN)` is `NaN` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_atan") +external public fun atan(x: Double): Double + +/** + * Returns the angle `theta` of the polar coordinates `(r, theta)` that correspond + * to the rectangular coordinates `(x, y)` by computing the arc tangent of the value [y] / [x]; + * the returned value is an angle in the range from `-PI` to `PI` radians. + * + * Special cases: + * - `atan2(0.0, 0.0)` is `0.0` + * - `atan2(0.0, x)` is `0.0` for `x > 0` and `PI` for `x < 0` + * - `atan2(-0.0, x)` is `-0.0` for 'x > 0` and `-PI` for `x < 0` + * - `atan2(y, +Inf)` is `0.0` for `0 < y < +Inf` and `-0.0` for '-Inf < y < 0` + * - `atan2(y, -Inf)` is `PI` for `0 < y < +Inf` and `-PI` for `-Inf < y < 0` + * - `atan2(y, 0.0)` is `PI/2` for `y > 0` and `-PI/2` for `y < 0` + * - `atan2(+Inf, x)` is `PI/2` for finite `x`y + * - `atan2(-Inf, x)` is `-PI/2` for finite `x` + * - `atan2(NaN, x)` and `atan2(y, NaN)` is `NaN` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_atan2") +external public fun atan2(y: Double, x: Double): Double + +/** + * Computes the hyperbolic sine of the value [x]. + * + * Special cases: + * - `sinh(NaN)` is `NaN` + * - `sinh(+Inf)` is `+Inf` + * - `sinh(-Inf)` is `-Inf` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_sinh") +external public fun sinh(x: Double): Double + +/** + * Computes the hyperbolic cosine of the value [x]. + * + * Special cases: + * - `cosh(NaN)` is `NaN` + * - `cosh(+Inf|-Inf)` is `+Inf` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_cosh") +external public fun cosh(x: Double): Double + +/** + * Computes the hyperbolic tangent of the value [x]. + * + * Special cases: + * - `tanh(NaN)` is `NaN` + * - `tanh(+Inf)` is `1.0` + * - `tanh(-Inf)` is `-1.0` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_tanh") +external public fun tanh(x: Double): Double + +/** + * Computes the inverse hyperbolic sine of the value [x]. + * + * The returned value is `y` such that `sinh(y) == x`. + * + * Special cases: + * - `asinh(NaN)` is `NaN` + * - `asinh(+Inf)` is `+Inf` + * - `asinh(-Inf)` is `-Inf` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_asinh") +external public fun asinh(x: Double): Double + +/** + * Computes the inverse hyperbolic cosine of the value [x]. + * + * The returned value is positive `y` such that `cosh(y) == x`. + * + * Special cases: + * - `acosh(NaN)` is `NaN` + * - `acosh(x)` is `NaN` when `x < 1` + * - `acosh(+Inf)` is `+Inf` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_acosh") +external public fun acosh(x: Double): Double + +/** + * Computes the inverse hyperbolic tangent of the value [x]. + * + * The returned value is `y` such that `tanh(y) == x`. + * + * 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") +@SymbolName("Kotlin_math_atanh") +external public fun atanh(x: Double): Double + +/** + * Computes `sqrt(x^2 + y^2)` without intermediate overflow or underflow. + * + * Special cases: + * - returns `+Inf` if any of arguments is infinite + * - returns `NaN` if any of arguments is `NaN` and the other is not infinite + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_hypot") +external public fun hypot(x: Double, y: Double): Double + +/** + * Computes the positive square root of the value [x]. + * + * Special cases: + * - `sqrt(x)` is `NaN` when `x < 0` or `x` is `NaN` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_sqrt") +external public fun sqrt(x: Double): Double + +/** + * Computes Euler's number `e` raised to the power of the value [x]. + * + * Special cases: + * - `exp(NaN)` is `NaN` + * - `exp(+Inf)` is `+Inf` + * - `exp(-Inf)` is `0.0` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_exp") +external public fun exp(x: Double): Double + +/** + * Computes `exp(x) - 1`. + * + * This function can be implemented to produce more precise result for [x] near zero. + * + * Special cases: + * - `expm1(NaN)` is `NaN` + * - `expm1(+Inf)` is `+Inf` + * - `expm1(-Inf)` is `-1.0` + * + * @see [exp] function. + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_expm1") +external public fun expm1(x: Double): Double + +/** + * Computes the logarithm of the value [x] to the given [base]. + * + * Special cases: + * - `log(x, b)` is `NaN` if either `x` or `b` are `NaN` + * - `log(x, b)` is `NaN` when `x < 0` or `b <= 0` or `b == 1.0` + * - `log(+Inf, +Inf)` is `NaN` + * - `log(+Inf, b)` is `+Inf` for `b > 1` and `-Inf` for `b < 1` + * - `log(0.0, b)` is `-Inf` for `b > 1` and `+Inf` for `b > 1` + * + * See also logarithm functions for common fixed bases: [ln], [log10] and [log2]. + */ +@SinceKotlin("1.2") +public fun log(x: Double, base: Double): Double { + if (base <= 0.0 || base == 1.0) return Double.NaN + return ln(x) / ln(base) +} + +/** + * Computes the natural logarithm (base `E`) of the value [x]. + * + * Special cases: + * - `ln(NaN)` is `NaN` + * - `ln(x)` is `NaN` when `x < 0.0` + * - `ln(+Inf)` is `+Inf` + * - `ln(0.0)` is `-Inf` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_ln") +external public fun ln(x: Double): Double + +/** + * Computes the common logarithm (base 10) of the value [x]. + * + * @see [ln] function for special cases. + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_log10") +external public fun log10(x: Double): Double + +/** + * Computes the binary logarithm (base 2) of the value [x]. + * + * @see [ln] function for special cases. + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_log2") +external public fun log2(x: Double): Double + +/** + * Computes `ln(x + 1)`. + * + * This function can be implemented to produce more precise result for [x] near zero. + * + * Special cases: + * - `ln1p(NaN)` is `NaN` + * - `ln1p(x)` is `NaN` where `x < -1.0` + * - `ln1p(-1.0)` is `-Inf` + * - `ln1p(+Inf)` is `+Inf` + * + * @see [ln] function + * @see [expm1] function + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_ln1p") +external public fun ln1p(x: Double): Double + +/** + * Rounds the given value [x] to an integer towards positive infinity. + + * @return the smallest double value that is greater than the given value [x] and is a mathematical integer. + * + * Special cases: + * - `ceil(x)` is `x` where `x` is `NaN` or `+Inf` or `-Inf` or already a mathematical integer. + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_ceil") +external public fun ceil(x: Double): Double + +/** + * Rounds the given value [x] to an integer towards negative infinity. + + * @return the largest double value that is smaller than the given value [x] and is a mathematical integer. + * + * Special cases: + * - `floor(x)` is `x` where `x` is `NaN` or `+Inf` or `-Inf` or already a mathematical integer. + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_floor") +external public fun floor(x: Double): Double + +/** + * Rounds the given value [x] to an integer towards zero. + * + * @return the value [x] having its fractional part truncated. + * + * Special cases: + * - `truncate(x)` is `x` where `x` is `NaN` or `+Inf` or `-Inf` or already a mathematical integer. + */ +@SinceKotlin("1.2") +public fun truncate(x: Double): Double = when { + x.isNaN() || x.isInfinite() -> x + x > 0 -> floor(x) + else -> ceil(x) +} + +/** + * Rounds the given value [x] towards the closest integer with ties rounded towards even integer. + * + * Special cases: + * - `round(x)` is `x` where `x` is `NaN` or `+Inf` or `-Inf` or already a mathematical integer. + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_round") +external public fun round(x: Double): Double + +/** + * Returns the absolute value of the given value [x]. + * + * Special cases: + * - `abs(NaN)` is `NaN` + * + * @see absoluteValue extension property for [Double] + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_abs") +external public fun abs(x: Double): Double + +/** + * Returns the sign of the given value [x]: + * - `-1.0` if the value is negative, + * - zero if the value is zero, + * - `1.0` if the value is positive + * + * Special case: + * - `sign(NaN)` is `NaN` + */ +@SinceKotlin("1.2") +public fun sign(x: Double): Double = when { + x.isNaN() -> Double.NaN + x > 0 -> 1.0 + x < 0 -> -1.0 + else -> x +} + +/** + * Returns the smaller of two values. + * + * If either value is `NaN`, then the result is `NaN`. + */ +@SinceKotlin("1.2") +public fun min(a: Double, b: Double): Double = when { + a.isNaN() || b.isNaN() -> Double.NaN + a == 0.0 && b == 0.0 -> if (a.signBit()) a else b // -0.0 < +0.0 + else -> if (a < b) a else b +} +/** + * Returns the greater of two values. + * + * If either value is `NaN`, then the result is `NaN`. + */ +@SinceKotlin("1.2") +public fun max(a: Double, b: Double): Double = when { + a.isNaN() || b.isNaN() -> Double.NaN + a == 0.0 && b == 0.0 -> if (!a.signBit()) a else b // -0.0 < +0.0 + else -> if (a > b) a else b +} + +// extensions + +/** + * Raises this value to the power [x]. + * + * Special cases: + * - `b.pow(0.0)` is `1.0` + * - `b.pow(1.0) == b` + * - `b.pow(NaN)` is `NaN` + * - `NaN.pow(x)` is `NaN` for `x != 0.0` + * - `b.pow(Inf)` is `NaN` for `abs(b) == 1.0` + * - `b.pow(x)` is `NaN` for `b < 0` and `x` is finite and not an integer + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_Double_pow") +external public fun Double.pow(x: Double): Double + +/** + * Raises this value to the integer power [n]. + * + * See the other overload of [pow] for details. + */ +@SinceKotlin("1.2") +public fun Double.pow(n: Int): Double = pow(n.toDouble()) + +/** + * Computes the remainder of division of this value by the [divisor] value according to the IEEE 754 standard. + * + * The result is computed as `r = this - (q * divisor)` where `q` is the quotient of division rounded to the nearest integer, + * `q = round(this / other)`. + * + * Special cases: + * - `x.IEEErem(y)` is `NaN`, when `x` is `NaN` or `y` is `NaN` or `x` is `+Inf|-Inf` or `y` is zero. + * - `x.IEEErem(y) == x` when `x` is finite and `y` is infinite. + * + * @see round + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_Double_IEEErem") +external public fun Double.IEEErem(divisor: Double): Double + +/** + * Returns the absolute value of this value. + * + * Special cases: + * - `NaN.absoluteValue` is `NaN` + * + * @see abs function + */ +@SinceKotlin("1.2") +public val Double.absoluteValue: Double + get() = abs(this) + +/** + * Returns the sign of this value: + * - `-1.0` if the value is negative, + * - zero if the value is zero, + * - `1.0` if the value is positive + * + * Special case: + * - `NaN.sign` is `NaN` + */ +@SinceKotlin("1.2") +public val Double.sign: Double + get() = sign(this) + +/** + * Returns this value with the sign bit same as of the [sign] value. + * + * If [sign] is `NaN` the sign of the result is undefined. + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_Double_withSign") +external public fun Double.withSign(sign: Double): Double + +/** + * Returns this value with the sign bit same as of the [sign] value. + */ +@SinceKotlin("1.2") +public fun Double.withSign(sign: Int): Double = withSign(sign.toDouble()) + +/** + * Returns the ulp (unit in the last place) of this value. + * + * An ulp is a positive distance between this value and the next nearest [Double] value larger in magnitude. + * + * Special Cases: + * - `NaN.ulp` is `NaN` + * - `x.ulp` is `+Inf` when `x` is `+Inf` or `-Inf` + * - `0.0.ulp` is `Double.MIN_VALUE` + */ +@SinceKotlin("1.2") +public val Double.ulp: Double + get() = when { + isNaN() -> Double.NaN + isInfinite() -> Double.POSITIVE_INFINITY + this == Double.MAX_VALUE || this == -Double.MAX_VALUE -> 2.0.pow(971) + else -> { + val d = absoluteValue + d.nextUp() - d + } + } + +/** + * Returns the [Double] value nearest to this value in direction of positive infinity. + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_Double_nextUp") +external public fun Double.nextUp(): Double +/** + * Returns the [Double] value nearest to this value in direction of negative infinity. + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_Double_nextDown") +external public fun Double.nextDown(): Double + +/** + * Returns the [Double] value nearest to this value in direction from this value towards the value [to]. + * + * Special cases: + * - `x.nextTowards(y)` is `NaN` if either `x` or `y` are `NaN` + * - `x.nextTowards(x) == x` + * + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_Double_nextTowards") +external public fun Double.nextTowards(to: Double): Double + +/** + * Returns true if the sign of [this] value is negative and false otherwise + */ +@SymbolName("Kotlin_math_Double_signBit") +external private fun Double.signBit(): Boolean + +/** + * Rounds this [Double] value to the nearest integer and converts the result to [Int]. + * Ties are rounded towards positive infinity. + * + * Special cases: + * - `x.roundToInt() == Int.MAX_VALUE` when `x > Int.MAX_VALUE` + * - `x.roundToInt() == Int.MIN_VALUE` when `x < Int.MIN_VALUE` + * + * @throws IllegalArgumentException when this value is `NaN` + */ +@SinceKotlin("1.2") +public fun Double.roundToInt(): Int = when { + isNaN() -> throw IllegalArgumentException("Cannot round NaN value.") + this > Int.MAX_VALUE -> Int.MAX_VALUE + this < Int.MIN_VALUE -> Int.MIN_VALUE + else -> floor(this + 0.5).toInt() +} + +/** + * Rounds this [Double] value to the nearest integer and converts the result to [Long]. + * Ties are rounded towards positive infinity. + * + * Special cases: + * - `x.roundToLong() == Long.MAX_VALUE` when `x > Long.MAX_VALUE` + * - `x.roundToLong() == Long.MIN_VALUE` when `x < Long.MIN_VALUE` + * + * @throws IllegalArgumentException when this value is `NaN` + */ +@SinceKotlin("1.2") +public fun Double.roundToLong(): Long = when { + isNaN() -> throw IllegalArgumentException("Cannot round NaN value.") + this > Long.MAX_VALUE -> Long.MAX_VALUE + this < Long.MIN_VALUE -> Long.MIN_VALUE + else -> floor(this + 0.5).toLong() +} + +// endregion + +// region ================ Float Math ======================================== + +/** Computes the sine of the angle [x] given in radians. + * + * Special cases: + * - `sin(NaN|+Inf|-Inf)` is `NaN` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_sinf") +external public fun sin(x: Float): Float + +/** Computes the cosine of the angle [x] given in radians. + * + * Special cases: + * - `cos(NaN|+Inf|-Inf)` is `NaN` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_cosf") +external public fun cos(x: Float): Float + +/** Computes the tangent of the angle [x] given in radians. + * + * Special cases: + * - `tan(NaN|+Inf|-Inf)` is `NaN` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_tanf") +external public fun tan(x: Float): Float + +/** + * Computes the arc sine of the value [x]; + * the returned value is an angle in the range from `-PI/2` to `PI/2` radians. + * + * Special cases: + * - `asin(x)` is `NaN`, when `abs(x) > 1` or x is `NaN` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_asinf") +external public fun asin(x: Float): Float + +/** + * Computes the arc cosine of the value [x]; + * the returned value is an angle in the range from `0.0` to `PI` radians. + * + * Special cases: + * - `acos(x)` is `NaN`, when `abs(x) > 1` or x is `NaN` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_acosf") +external public fun acos(x: Float): Float + +/** + * Computes the arc tangent of the value [x]; + * the returned value is an angle in the range from `-PI/2` to `PI/2` radians. + * + * Special cases: + * - `atan(NaN)` is `NaN` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_atanf") +external public fun atan(x: Float): Float + +/** + * Returns the angle `theta` of the polar coordinates `(r, theta)` that correspond + * to the rectangular coordinates `(x, y)` by computing the arc tangent of the value [y] / [x]; + * the returned value is an angle in the range from `-PI` to `PI` radians. + * + * Special cases: + * - `atan2(0.0, 0.0)` is `0.0` + * - `atan2(0.0, x)` is `0.0` for `x > 0` and `PI` for `x < 0` + * - `atan2(-0.0, x)` is `-0.0` for 'x > 0` and `-PI` for `x < 0` + * - `atan2(y, +Inf)` is `0.0` for `0 < y < +Inf` and `-0.0` for '-Inf < y < 0` + * - `atan2(y, -Inf)` is `PI` for `0 < y < +Inf` and `-PI` for `-Inf < y < 0` + * - `atan2(y, 0.0)` is `PI/2` for `y > 0` and `-PI/2` for `y < 0` + * - `atan2(+Inf, x)` is `PI/2` for finite `x`y + * - `atan2(-Inf, x)` is `-PI/2` for finite `x` + * - `atan2(NaN, x)` and `atan2(y, NaN)` is `NaN` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_atan2f") +external public fun atan2(y: Float, x: Float): Float + +/** + * Computes the hyperbolic sine of the value [x]. + * + * Special cases: + * - `sinh(NaN)` is `NaN` + * - `sinh(+Inf)` is `+Inf` + * - `sinh(-Inf)` is `-Inf` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_sinhf") +external public fun sinh(x: Float): Float + +/** + * Computes the hyperbolic cosine of the value [x]. + * + * Special cases: + * - `cosh(NaN)` is `NaN` + * - `cosh(+Inf|-Inf)` is `+Inf` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_coshf") +external public fun cosh(x: Float): Float + +/** + * Computes the hyperbolic tangent of the value [x]. + * + * Special cases: + * - `tanh(NaN)` is `NaN` + * - `tanh(+Inf)` is `1.0` + * - `tanh(-Inf)` is `-1.0` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_tanhf") +external public fun tanh(x: Float): Float + +/** + * Computes the inverse hyperbolic sine of the value [x]. + * + * The returned value is `y` such that `sinh(y) == x`. + * + * Special cases: + * - `asinh(NaN)` is `NaN` + * - `asinh(+Inf)` is `+Inf` + * - `asinh(-Inf)` is `-Inf` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_asinhf") +external public fun asinh(x: Float): Float + +/** + * Computes the inverse hyperbolic cosine of the value [x]. + * + * The returned value is positive `y` such that `cosh(y) == x`. + * + * Special cases: + * - `acosh(NaN)` is `NaN` + * - `acosh(x)` is `NaN` when `x < 1` + * - `acosh(+Inf)` is `+Inf` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_acoshf") +external public fun acosh(x: Float): Float + +/** + * Computes the inverse hyperbolic tangent of the value [x]. + * + * The returned value is `y` such that `tanh(y) == x`. + * + * 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") +@SymbolName("Kotlin_math_atanhf") +external public fun atanh(x: Float): Float + +/** + * Computes `sqrt(x^2 + y^2)` without intermediate overflow or underflow. + * + * Special cases: + * - returns `+Inf` if any of arguments is infinite + * - returns `NaN` if any of arguments is `NaN` and the other is not infinite + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_hypotf") +external public fun hypot(x: Float, y: Float): Float + +/** + * Computes the positive square root of the value [x]. + * + * Special cases: + * - `sqrt(x)` is `NaN` when `x < 0` or `x` is `NaN` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_sqrtf") +external public fun sqrt(x: Float): Float + +/** + * Computes Euler's number `e` raised to the power of the value [x]. + * + * Special cases: + * - `exp(NaN)` is `NaN` + * - `exp(+Inf)` is `+Inf` + * - `exp(-Inf)` is `0.0` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_expf") +external public fun exp(x: Float): Float + +/** + * Computes `exp(x) - 1`. + * + * This function can be implemented to produce more precise result for [x] near zero. + * + * Special cases: + * - `expm1(NaN)` is `NaN` + * - `expm1(+Inf)` is `+Inf` + * - `expm1(-Inf)` is `-1.0` + * + * @see [exp] function. + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_expm1f") +external public fun expm1(x: Float): Float + +/** + * Computes the logarithm of the value [x] to the given [base]. + * + * Special cases: + * - `log(x, b)` is `NaN` if either `x` or `b` are `NaN` + * - `log(x, b)` is `NaN` when `x < 0` or `b <= 0` or `b == 1.0` + * - `log(+Inf, +Inf)` is `NaN` + * - `log(+Inf, b)` is `+Inf` for `b > 1` and `-Inf` for `b < 1` + * - `log(0.0, b)` is `-Inf` for `b > 1` and `+Inf` for `b > 1` + * + * See also logarithm functions for common fixed bases: [ln], [log10] and [log2]. + */ +@SinceKotlin("1.2") +public fun log(x: Float, base: Float): Float { + if (base <= 0.0F || base == 1.0F) return Float.NaN + return ln(x) / ln(base) +} + +/** + * Computes the natural logarithm (base `E`) of the value [x]. + * + * Special cases: + * - `ln(NaN)` is `NaN` + * - `ln(x)` is `NaN` when `x < 0.0` + * - `ln(+Inf)` is `+Inf` + * - `ln(0.0)` is `-Inf` + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_lnf") +external public fun ln(x: Float): Float + +/** + * Computes the common logarithm (base 10) of the value [x]. + * + * @see [ln] function for special cases. + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_log10f") +external public fun log10(x: Float): Float + +/** + * Computes the binary logarithm (base 2) of the value [x]. + * + * @see [ln] function for special cases. + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_log2f") +external public fun log2(x: Float): Float + +/** + * Computes `ln(a + 1)`. + * + * This function can be implemented to produce more precise result for [x] near zero. + * + * Special cases: + * - `ln1p(NaN)` is `NaN` + * - `ln1p(x)` is `NaN` where `x < -1.0` + * - `ln1p(-1.0)` is `-Inf` + * - `ln1p(+Inf)` is `+Inf` + * + * @see [ln] function + * @see [expm1] function + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_ln1pf") +external public fun ln1p(x: Float): Float + +/** + * Rounds the given value [x] to an integer towards positive infinity. + + * @return the smallest Float value that is greater than the given value [x] and is a mathematical integer. + * + * Special cases: + * - `ceil(x)` is `x` where `x` is `NaN` or `+Inf` or `-Inf` or already a mathematical integer. + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_ceilf") +external public fun ceil(x: Float): Float + +/** + * Rounds the given value [x] to an integer towards negative infinity. + + * @return the largest Float value that is smaller than the given value [x] and is a mathematical integer. + * + * Special cases: + * - `floor(x)` is `x` where `x` is `NaN` or `+Inf` or `-Inf` or already a mathematical integer. + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_floorf") +external public fun floor(x: Float): Float + +/** + * Rounds the given value [x] to an integer towards zero. + * + * @return the value [x] having its fractional part truncated. + * + * Special cases: + * - `truncate(x)` is `x` where `x` is `NaN` or `+Inf` or `-Inf` or already a mathematical integer. + */ +@SinceKotlin("1.2") +public fun truncate(x: Float): Float = when { + x.isNaN() || x.isInfinite() -> x + x > 0 -> floor(x) + else -> ceil(x) +} + +/** + * Rounds the given value [x] towards the closest integer with ties rounded towards even integer. + * + * Special cases: + * - `round(x)` is `x` where `x` is `NaN` or `+Inf` or `-Inf` or already a mathematical integer. + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_roundf") +external public fun round(x: Float): Float + + +/** + * Returns the absolute value of the given value [x]. + * + * Special cases: + * - `abs(NaN)` is `NaN` + * + * @see absoluteValue extension property for [Float] + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_absf") +external public fun abs(x: Float): Float + +/** + * Returns the sign of the given value [x]: + * - `-1.0` if the value is negative, + * - zero if the value is zero, + * - `1.0` if the value is positive + * + * Special case: + * - `sign(NaN)` is `NaN` + */ +@SinceKotlin("1.2") +public fun sign(x: Float): Float = when { + x.isNaN() -> Float.NaN + x > 0 -> 1.0f + x < 0 -> -1.0f + else -> x +} + +/** + * Returns the smaller of two values. + * + * If either value is `NaN`, then the result is `NaN`. + */ +@SinceKotlin("1.2") +public fun min(a: Float, b: Float): Float = when { + a.isNaN() || b.isNaN() -> Float.NaN + a == 0.0f && b == 0.0f -> if (a.signBit()) a else b // -0.0 < +0.0 + else -> if (a < b) a else b +} +/** + * Returns the greater of two values. + * + * If either value is `NaN`, then the result is `NaN`. + */ +@SinceKotlin("1.2") +public fun max(a: Float, b: Float): Float = when { + a.isNaN() || b.isNaN() -> Float.NaN + a == 0.0f && b == 0.0f -> if (!a.signBit()) a else b // -0.0 < +0.0 + else -> if (a > b) a else b +} + +// extensions + +/** + * Raises this value to the power [x]. + * + * Special cases: + * - `b.pow(0.0)` is `1.0` + * - `b.pow(1.0) == b` + * - `b.pow(NaN)` is `NaN` + * - `NaN.pow(x)` is `NaN` for `x != 0.0` + * - `b.pow(Inf)` is `NaN` for `abs(b) == 1.0` + * - `b.pow(x)` is `NaN` for `b < 0` and `x` is finite and not an integer + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_Float_pow") +external public fun Float.pow(x: Float): Float + +/** + * Raises this value to the integer power [n]. + * + * See the other overload of [pow] for details. + */ +@SinceKotlin("1.2") +public fun Float.pow(n: Int): Float = pow(n.toFloat()) + +/** + * Computes the remainder of division of this value by the [divisor] value according to the IEEE 754 standard. + * + * The result is computed as `r = this - (q * divisor)` where `q` is the quotient of division rounded to the nearest integer, + * `q = round(this / other)`. + * + * Special cases: + * - `x.IEEErem(y)` is `NaN`, when `x` is `NaN` or `y` is `NaN` or `x` is `+Inf|-Inf` or `y` is zero. + * - `x.IEEErem(y) == x` when `x` is finite and `y` is infinite. + * + * @see round + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_Float_IEEErem") +external public fun Float.IEEErem(divisor: Float): Float + +/** + * Returns the absolute value of this value. + * + * Special cases: + * - `NaN.absoluteValue` is `NaN` + * + * @see abs function + */ +@SinceKotlin("1.2") +public val Float.absoluteValue: Float + get() = abs(this) + +/** + * Returns the sign of this value: + * - `-1.0` if the value is negative, + * - zero if the value is zero, + * - `1.0` if the value is positive + * + * Special case: + * - `NaN.sign` is `NaN` + */ +@SinceKotlin("1.2") +public val Float.sign: Float + get() = sign(this) + +/** + * Returns this value with the sign bit same as of the [sign] value. + * + * If [sign] is `NaN` the sign of the result is undefined. + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_Float_withSign") +external public fun Float.withSign(sign: Float): Float +/** + * Returns this value with the sign bit same as of the [sign] value. + */ +@SinceKotlin("1.2") +public fun Float.withSign(sign: Int): Float = withSign(sign.toFloat()) + +@SinceKotlin("1.2") +public val Float.ulp: Float + get() = when { + isNaN() -> Float.NaN + isInfinite() -> Float.POSITIVE_INFINITY + this == Float.MAX_VALUE || this == -Float.MAX_VALUE -> 2.0f.pow(104) + else -> { + val d = absoluteValue + d.nextUp() - d + } + } + +/** + * Returns the [Float] value nearest to this value in direction of positive infinity. + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_Float_nextUp") +external public fun Float.nextUp(): Float +/** + * Returns the [Float] value nearest to this value in direction of negative infinity. + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_Float_nextDown") +external public fun Float.nextDown(): Float + +/** + * Returns the [Float] value nearest to this value in direction from this value towards the value [to]. + * + * Special cases: + * - `x.nextTowards(y)` is `NaN` if either `x` or `y` are `NaN` + * - `x.nextTowards(x) == x` + * + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_Float_nextTowards") +external public fun Float.nextTowards(to: Float): Float + +/** + * Returns true if the sign of [this] value is negative and false otherwise + */ +@SymbolName("Kotlin_math_Float_signBit") +external private fun Float.signBit(): Boolean + +/** + * Rounds this [Float] value to the nearest integer and converts the result to [Int]. + * Ties are rounded towards positive infinity. + * + * Special cases: + * - `x.roundToInt() == Int.MAX_VALUE` when `x > Int.MAX_VALUE` + * - `x.roundToInt() == Int.MIN_VALUE` when `x < Int.MIN_VALUE` + * + * @throws IllegalArgumentException when this value is `NaN` + */ +@SinceKotlin("1.2") +public fun Float.roundToInt(): Int = when { + isNaN() -> throw IllegalArgumentException("Cannot round NaN value.") + this > Int.MAX_VALUE -> Int.MAX_VALUE + this < Int.MIN_VALUE -> Int.MIN_VALUE + else -> floor(this + 0.5f).toInt() +} + +/** + * Rounds this [Float] value to the nearest integer and converts the result to [Long]. + * Ties are rounded towards positive infinity. + * + * Special cases: + * - `x.roundToLong() == Long.MAX_VALUE` when `x > Long.MAX_VALUE` + * - `x.roundToLong() == Long.MIN_VALUE` when `x < Long.MIN_VALUE` + * + * @throws IllegalArgumentException when this value is `NaN` + */ +@SinceKotlin("1.2") +public fun Float.roundToLong(): Long = when { + isNaN() -> throw IllegalArgumentException("Cannot round NaN value.") + this > Long.MAX_VALUE -> Long.MAX_VALUE + this < Long.MIN_VALUE -> Long.MIN_VALUE + else -> floor(this + 0.5f).toLong() +} + +// endregion + +// region ================ Integer Math ======================================== + +/** + * Returns the absolute value of the given value [n]. + * + * Special cases: + * - `abs(Int.MIN_VALUE)` is `Int.MIN_VALUE` due to an overflow + * + * @see absoluteValue extension property for [Int] + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_absi") +external public fun abs(n: Int): Int + +/** + * Returns the smaller of two values. + */ +@SinceKotlin("1.2") +public fun min(a: Int, b: Int): Int = if (a < b) a else b + +/** + * Returns the greater of two values. + */ +@SinceKotlin("1.2") +public fun max(a: Int, b: Int): Int = if (a > b) a else b + +/** + * Returns the absolute value of this value. + * + * Special cases: + * - `Int.MIN_VALUE.absoluteValue` is `Int.MIN_VALUE` due to an overflow + * + * @see abs function + */ +@SinceKotlin("1.2") +public val Int.absoluteValue: Int + get() = abs(this) + +/** + * Returns the sign of this value: + * - `-1` if the value is negative, + * - `0` if the value is zero, + * - `1` if the value is positive + */ +@SinceKotlin("1.2") +public val Int.sign: Int + get() = when { + this < 0 -> -1 + this > 0 -> 1 + else -> 0 + } + + +/** + * Returns the absolute value of the given value [n]. + * + * Special cases: + * - `abs(Long.MIN_VALUE)` is `Long.MIN_VALUE` due to an overflow + * + * @see absoluteValue extension property for [Long] + */ +@SinceKotlin("1.2") +@SymbolName("Kotlin_math_absl") +external public fun abs(n: Long): Long + +/** + * Returns the smaller of two values. + */ +@SinceKotlin("1.2") +public fun min(a: Long, b: Long): Long = if (a < b) a else b + +/** + * Returns the greater of two values. + */ +@SinceKotlin("1.2") +public fun max(a: Long, b: Long): Long = if (a > b) a else b + +/** + * Returns the absolute value of this value. + * + * Special cases: + * - `Long.MIN_VALUE.absoluteValue` is `Long.MIN_VALUE` due to an overflow + * + * @see abs function + */ +@SinceKotlin("1.2") +public val Long.absoluteValue: Long + get() = abs(this) + +/** + * Returns the sign of this value: + * - `-1` if the value is negative, + * - `0` if the value is zero, + * - `1` if the value is positive + */ +@SinceKotlin("1.2") +public val Long.sign: Int + get() = when { + this < 0 -> -1 + this > 0 -> 1 + else -> 0 + } + +// endregion \ No newline at end of file