[libc-commits] [libc] 118c13c - [libc] Add implementation of few floating point manipulation functions.

Siva Chandra Reddy via libc-commits libc-commits at lists.llvm.org
Thu Jun 11 12:23:21 PDT 2020


Author: Siva Chandra Reddy
Date: 2020-06-11T12:23:11-07:00
New Revision: 118c13c691a5b3b0c5760061a89d5ef7a319c15b

URL: https://github.com/llvm/llvm-project/commit/118c13c691a5b3b0c5760061a89d5ef7a319c15b
DIFF: https://github.com/llvm/llvm-project/commit/118c13c691a5b3b0c5760061a89d5ef7a319c15b.diff

LOG: [libc] Add implementation of few floating point manipulation functions.

Implementations of copysign[f], frexp[f], logb[f], and modf[f] are added.

Reviewers: asteinhauser

Differential Revision: https://reviews.llvm.org/D81134

Added: 
    libc/src/math/copysign.cpp
    libc/src/math/copysign.h
    libc/src/math/copysignf.cpp
    libc/src/math/copysignf.h
    libc/src/math/frexp.cpp
    libc/src/math/frexp.h
    libc/src/math/frexpf.cpp
    libc/src/math/frexpf.h
    libc/src/math/logb.cpp
    libc/src/math/logb.h
    libc/src/math/logbf.cpp
    libc/src/math/logbf.h
    libc/src/math/modf.cpp
    libc/src/math/modf.h
    libc/src/math/modff.cpp
    libc/src/math/modff.h
    libc/test/src/math/copysign_test.cpp
    libc/test/src/math/copysignf_test.cpp
    libc/test/src/math/frexp_test.cpp
    libc/test/src/math/frexpf_test.cpp
    libc/test/src/math/logb_test.cpp
    libc/test/src/math/logbf_test.cpp
    libc/test/src/math/modf_test.cpp
    libc/test/src/math/modff_test.cpp
    libc/utils/FPUtil/ManipulationFunctions.h

Modified: 
    libc/config/linux/aarch64/entrypoints.txt
    libc/config/linux/api.td
    libc/config/linux/x86_64/entrypoints.txt
    libc/spec/stdc.td
    libc/src/math/CMakeLists.txt
    libc/test/src/math/CMakeLists.txt
    libc/utils/FPUtil/BitPatterns.h
    libc/utils/FPUtil/CMakeLists.txt
    libc/utils/FPUtil/FloatOperations.h

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index ca3157b295e8..044b0b5ae0ec 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -8,6 +8,8 @@ set(TARGET_LIBC_ENTRYPOINTS
 
 set(TARGET_LIBM_ENTRYPOINTS
     # math.h entrypoints
+    libc.src.math.copysign
+    libc.src.math.copysignf
     libc.src.math.ceil
     libc.src.math.ceilf
     libc.src.math.cosf
@@ -17,6 +19,12 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.fabsf
     libc.src.math.floor
     libc.src.math.floorf
+    libc.src.math.frexp
+    libc.src.math.frexpf
+    libc.src.math.logb
+    libc.src.math.logbf
+    libc.src.math.modf
+    libc.src.math.modff
     libc.src.math.round
     libc.src.math.roundf
     libc.src.math.sincosf

diff  --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index 1d20c5fd12b0..f2b7050661d3 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -150,6 +150,8 @@ def MathAPI : PublicAPI<"math.h"> {
     FloatT,
   ];
   let Functions = [
+   "copysign",
+   "copysignf",
    "ceil",
    "ceilf",
    "cosf",
@@ -157,6 +159,12 @@ def MathAPI : PublicAPI<"math.h"> {
    "fabsf",
    "floor",
    "floorf",
+   "frexp",
+   "frexpf",
+   "logb",
+   "logbf",
+   "modf",
+   "modff",
    "expf",
    "exp2f",
    "round",

diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index a6bc492ac67e..93b0dfdcb3f3 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -45,6 +45,8 @@ set(TARGET_LIBC_ENTRYPOINTS
 
 set(TARGET_LIBM_ENTRYPOINTS
     # math.h entrypoints
+    libc.src.math.copysign
+    libc.src.math.copysignf
     libc.src.math.ceil
     libc.src.math.ceilf
     libc.src.math.cosf
@@ -54,6 +56,12 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.fabsf
     libc.src.math.floor
     libc.src.math.floorf
+    libc.src.math.frexp
+    libc.src.math.frexpf
+    libc.src.math.logb
+    libc.src.math.logbf
+    libc.src.math.modf
+    libc.src.math.modff
     libc.src.math.round
     libc.src.math.roundf
     libc.src.math.sincosf

diff  --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index a9bdfbd710ae..b31f89d3d73a 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -20,6 +20,8 @@ def StdC : StandardSpec<"stdc"> {
   PtrType ThrdTTypePtr = PtrType<ThrdTType>;
 
   PtrType IntPtr = PtrType<IntType>;
+  PtrType FloatPtr = PtrType<FloatType>;
+  PtrType DoublePtr = PtrType<DoubleType>;
 
   NamedType SigHandlerT = NamedType<"__sighandler_t">;
 
@@ -187,6 +189,9 @@ def StdC : StandardSpec<"stdc"> {
       ],
       [], // Enumerations
       [
+          FunctionSpec<"copysign", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>]>,
+          FunctionSpec<"copysignf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<FloatType>]>,
+
           FunctionSpec<"ceil", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
           FunctionSpec<"ceilf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
 
@@ -196,6 +201,15 @@ def StdC : StandardSpec<"stdc"> {
           FunctionSpec<"floor", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
           FunctionSpec<"floorf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
 
+          FunctionSpec<"frexp", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntPtr>]>,
+          FunctionSpec<"frexpf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<IntPtr>]>,
+
+          FunctionSpec<"logb", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
+          FunctionSpec<"logbf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
+
+          FunctionSpec<"modf", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<DoublePtr>]>,
+          FunctionSpec<"modff", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<FloatPtr>]>,
+
           FunctionSpec<"cosf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
           FunctionSpec<"sinf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
 

diff  --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index 701ee6eb0448..c74e7e4ab5ff 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -189,3 +189,83 @@ add_entrypoint_object(
     .math_utils
     libc.include.math
 )
+
+add_entrypoint_object(
+  copysign
+  SRCS
+    copysign.cpp
+  HDRS
+    copysign.h
+  DEPENDS
+    libc.utils.FPUtil.fputil
+)
+
+add_entrypoint_object(
+  copysignf
+  SRCS
+    copysignf.cpp
+  HDRS
+    copysignf.h
+  DEPENDS
+    libc.utils.FPUtil.fputil
+)
+
+add_entrypoint_object(
+  frexp
+  SRCS
+    frexp.cpp
+  HDRS
+    frexp.h
+  DEPENDS
+    libc.utils.FPUtil.fputil
+)
+
+add_entrypoint_object(
+  frexpf
+  SRCS
+    frexpf.cpp
+  HDRS
+    frexpf.h
+  DEPENDS
+    libc.utils.FPUtil.fputil
+)
+
+add_entrypoint_object(
+  logb
+  SRCS
+    logb.cpp
+  HDRS
+    logb.h
+  DEPENDS
+    libc.utils.FPUtil.fputil
+)
+
+add_entrypoint_object(
+  logbf
+  SRCS
+    logbf.cpp
+  HDRS
+    logbf.h
+  DEPENDS
+    libc.utils.FPUtil.fputil
+)
+
+add_entrypoint_object(
+  modf
+  SRCS
+    modf.cpp
+  HDRS
+    modf.h
+  DEPENDS
+    libc.utils.FPUtil.fputil
+)
+
+add_entrypoint_object(
+  modff
+  SRCS
+    modff.cpp
+  HDRS
+    modff.h
+  DEPENDS
+    libc.utils.FPUtil.fputil
+)

diff  --git a/libc/src/math/copysign.cpp b/libc/src/math/copysign.cpp
new file mode 100644
index 000000000000..5eee71f98123
--- /dev/null
+++ b/libc/src/math/copysign.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of copysign function -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/common.h"
+#include "utils/FPUtil/ManipulationFunctions.h"
+
+namespace __llvm_libc {
+
+double LLVM_LIBC_ENTRYPOINT(copysign)(double x, double y) {
+  return fputil::copysign(x, y);
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/math/copysign.h b/libc/src/math/copysign.h
new file mode 100644
index 000000000000..edffe1b082fe
--- /dev/null
+++ b/libc/src/math/copysign.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for copysign ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_COPYSIGN_H
+#define LLVM_LIBC_SRC_MATH_COPYSIGN_H
+
+namespace __llvm_libc {
+
+double copysign(double x, double y);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_COPYSIGN_H

diff  --git a/libc/src/math/copysignf.cpp b/libc/src/math/copysignf.cpp
new file mode 100644
index 000000000000..c730dd37b7ae
--- /dev/null
+++ b/libc/src/math/copysignf.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of copysignf function ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/common.h"
+#include "utils/FPUtil/ManipulationFunctions.h"
+
+namespace __llvm_libc {
+
+float LLVM_LIBC_ENTRYPOINT(copysignf)(float x, float y) {
+  return fputil::copysign(x, y);
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/math/copysignf.h b/libc/src/math/copysignf.h
new file mode 100644
index 000000000000..5b7f1132252d
--- /dev/null
+++ b/libc/src/math/copysignf.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for copysignf ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_COPYSIGNF_H
+#define LLVM_LIBC_SRC_MATH_COPYSIGNF_H
+
+namespace __llvm_libc {
+
+float copysignf(float x, float y);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_COPYSIGNF_H

diff  --git a/libc/src/math/frexp.cpp b/libc/src/math/frexp.cpp
new file mode 100644
index 000000000000..8449929347bb
--- /dev/null
+++ b/libc/src/math/frexp.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of frexp function ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/common.h"
+#include "utils/FPUtil/ManipulationFunctions.h"
+
+namespace __llvm_libc {
+
+double LLVM_LIBC_ENTRYPOINT(frexp)(double x, int *exp) {
+  return fputil::frexp(x, *exp);
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/math/frexp.h b/libc/src/math/frexp.h
new file mode 100644
index 000000000000..925824318836
--- /dev/null
+++ b/libc/src/math/frexp.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for frexp -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_FREXP_H
+#define LLVM_LIBC_SRC_MATH_FREXP_H
+
+namespace __llvm_libc {
+
+double frexp(double x, int *exp);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_FREXP_H

diff  --git a/libc/src/math/frexpf.cpp b/libc/src/math/frexpf.cpp
new file mode 100644
index 000000000000..94dac9f59030
--- /dev/null
+++ b/libc/src/math/frexpf.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of frexpf function ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/common.h"
+#include "utils/FPUtil/ManipulationFunctions.h"
+
+namespace __llvm_libc {
+
+float LLVM_LIBC_ENTRYPOINT(frexpf)(float x, int *exp) {
+  return fputil::frexp(x, *exp);
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/math/frexpf.h b/libc/src/math/frexpf.h
new file mode 100644
index 000000000000..ed303d2c76dd
--- /dev/null
+++ b/libc/src/math/frexpf.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for frexpf ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_FREXPF_H
+#define LLVM_LIBC_SRC_MATH_FREXPF_H
+
+namespace __llvm_libc {
+
+float frexpf(float x, int *exp);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_FREXPF_H

diff  --git a/libc/src/math/logb.cpp b/libc/src/math/logb.cpp
new file mode 100644
index 000000000000..7475785ebf7e
--- /dev/null
+++ b/libc/src/math/logb.cpp
@@ -0,0 +1,16 @@
+//===-- Implementation of logb function -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/common.h"
+#include "utils/FPUtil/ManipulationFunctions.h"
+
+namespace __llvm_libc {
+
+double LLVM_LIBC_ENTRYPOINT(logb)(double x) { return fputil::logb(x); }
+
+} // namespace __llvm_libc

diff  --git a/libc/src/math/logb.h b/libc/src/math/logb.h
new file mode 100644
index 000000000000..b875dcd702ba
--- /dev/null
+++ b/libc/src/math/logb.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for logb --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_LOGB_H
+#define LLVM_LIBC_SRC_MATH_LOGB_H
+
+namespace __llvm_libc {
+
+double logb(double x);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_LOGB_H

diff  --git a/libc/src/math/logbf.cpp b/libc/src/math/logbf.cpp
new file mode 100644
index 000000000000..bfe8e8590b97
--- /dev/null
+++ b/libc/src/math/logbf.cpp
@@ -0,0 +1,16 @@
+//===-- Implementation of logbf function ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/common.h"
+#include "utils/FPUtil/ManipulationFunctions.h"
+
+namespace __llvm_libc {
+
+float LLVM_LIBC_ENTRYPOINT(logbf)(float x) { return fputil::logb(x); }
+
+} // namespace __llvm_libc

diff  --git a/libc/src/math/logbf.h b/libc/src/math/logbf.h
new file mode 100644
index 000000000000..46dcd3c91d62
--- /dev/null
+++ b/libc/src/math/logbf.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for logbf -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_LOGBF_H
+#define LLVM_LIBC_SRC_MATH_LOGBF_H
+
+namespace __llvm_libc {
+
+float logbf(float x);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_LOGBF_H

diff  --git a/libc/src/math/modf.cpp b/libc/src/math/modf.cpp
new file mode 100644
index 000000000000..51466004111b
--- /dev/null
+++ b/libc/src/math/modf.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of modf function -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/common.h"
+#include "utils/FPUtil/ManipulationFunctions.h"
+
+namespace __llvm_libc {
+
+double LLVM_LIBC_ENTRYPOINT(modf)(double x, double *iptr) {
+  return fputil::modf(x, *iptr);
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/math/modf.h b/libc/src/math/modf.h
new file mode 100644
index 000000000000..1dc732f6e89a
--- /dev/null
+++ b/libc/src/math/modf.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for modf --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_MODF_H
+#define LLVM_LIBC_SRC_MATH_MODF_H
+
+namespace __llvm_libc {
+
+double modf(double x, double *iptr);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_MODF_H

diff  --git a/libc/src/math/modff.cpp b/libc/src/math/modff.cpp
new file mode 100644
index 000000000000..4847fe24a9ec
--- /dev/null
+++ b/libc/src/math/modff.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of modf function -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/common.h"
+#include "utils/FPUtil/ManipulationFunctions.h"
+
+namespace __llvm_libc {
+
+float LLVM_LIBC_ENTRYPOINT(modff)(float x, float *iptr) {
+  return fputil::modf(x, *iptr);
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/math/modff.h b/libc/src/math/modff.h
new file mode 100644
index 000000000000..21457e0d2e81
--- /dev/null
+++ b/libc/src/math/modff.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for modff -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_MODFF_H
+#define LLVM_LIBC_SRC_MATH_MODFF_H
+
+namespace __llvm_libc {
+
+float modff(float x, float *iptr);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_MODFF_H

diff  --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index c381ea8a2e81..ebc03d3452cc 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -228,3 +228,99 @@ add_math_unittest(
     libc.src.math.exp2f
     libc.utils.FPUtil.fputil
 )
+
+add_math_unittest(
+  copysign_test
+  SUITE
+    libc_math_unittests
+  SRCS
+    copysign_test.cpp
+  DEPENDS
+    libc.include.math
+    libc.src.math.copysign
+    libc.utils.FPUtil.fputil
+)
+
+add_math_unittest(
+  copysignf_test
+  SUITE
+    libc_math_unittests
+  SRCS
+    copysignf_test.cpp
+  DEPENDS
+    libc.include.math
+    libc.src.math.copysignf
+    libc.utils.FPUtil.fputil
+)
+
+add_math_unittest(
+  frexp_test
+  SUITE
+    libc_math_unittests
+  SRCS
+    frexp_test.cpp
+  DEPENDS
+    libc.include.math
+    libc.src.math.frexp
+    libc.utils.FPUtil.fputil
+)
+
+add_math_unittest(
+  frexpf_test
+  SUITE
+    libc_math_unittests
+  SRCS
+    frexpf_test.cpp
+  DEPENDS
+    libc.include.math
+    libc.src.math.frexpf
+    libc.utils.FPUtil.fputil
+)
+
+add_math_unittest(
+  logb_test
+  SUITE
+    libc_math_unittests
+  SRCS
+    logb_test.cpp
+  DEPENDS
+    libc.include.math
+    libc.src.math.logb
+    libc.utils.FPUtil.fputil
+)
+
+add_math_unittest(
+  logbf_test
+  SUITE
+    libc_math_unittests
+  SRCS
+    logbf_test.cpp
+  DEPENDS
+    libc.include.math
+    libc.src.math.logbf
+    libc.utils.FPUtil.fputil
+)
+
+add_math_unittest(
+  modf_test
+  SUITE
+    libc_math_unittests
+  SRCS
+    modf_test.cpp
+  DEPENDS
+    libc.include.math
+    libc.src.math.modf
+    libc.utils.FPUtil.fputil
+)
+
+add_math_unittest(
+  modff_test
+  SUITE
+    libc_math_unittests
+  SRCS
+    modff_test.cpp
+  DEPENDS
+    libc.include.math
+    libc.src.math.modff
+    libc.utils.FPUtil.fputil
+)

diff  --git a/libc/test/src/math/copysign_test.cpp b/libc/test/src/math/copysign_test.cpp
new file mode 100644
index 000000000000..e0638467c5b9
--- /dev/null
+++ b/libc/test/src/math/copysign_test.cpp
@@ -0,0 +1,63 @@
+//===-- Unittests for copysign --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "include/math.h"
+#include "src/math/copysign.h"
+#include "utils/FPUtil/BitPatterns.h"
+#include "utils/FPUtil/FloatOperations.h"
+#include "utils/FPUtil/FloatProperties.h"
+#include "utils/UnitTest/Test.h"
+
+using __llvm_libc::fputil::valueAsBits;
+using __llvm_libc::fputil::valueFromBits;
+
+using BitPatterns = __llvm_libc::fputil::BitPatterns<double>;
+using Properties = __llvm_libc::fputil::FloatProperties<double>;
+
+TEST(CopySignTest, SpecialNumbers) {
+  EXPECT_EQ(BitPatterns::aNegativeQuietNaN,
+            valueAsBits(__llvm_libc::copysign(
+                valueFromBits(BitPatterns::aQuietNaN), -1.0)));
+  EXPECT_EQ(BitPatterns::aQuietNaN,
+            valueAsBits(__llvm_libc::copysign(
+                valueFromBits(BitPatterns::aNegativeQuietNaN), 1.0)));
+
+  EXPECT_EQ(BitPatterns::aNegativeSignallingNaN,
+            valueAsBits(__llvm_libc::copysign(
+                valueFromBits(BitPatterns::aSignallingNaN), -1.0)));
+  EXPECT_EQ(BitPatterns::aSignallingNaN,
+            valueAsBits(__llvm_libc::copysign(
+                valueFromBits(BitPatterns::aNegativeSignallingNaN), 1.0)));
+
+  EXPECT_EQ(BitPatterns::negInf, valueAsBits(__llvm_libc::copysign(
+                                     valueFromBits(BitPatterns::inf), -1.0)));
+  EXPECT_EQ(BitPatterns::inf, valueAsBits(__llvm_libc::copysign(
+                                  valueFromBits(BitPatterns::negInf), 1.0)));
+
+  EXPECT_EQ(BitPatterns::negZero, valueAsBits(__llvm_libc::copysign(
+                                      valueFromBits(BitPatterns::zero), -1.0)));
+  EXPECT_EQ(BitPatterns::zero, valueAsBits(__llvm_libc::copysign(
+                                   valueFromBits(BitPatterns::negZero), 1.0)));
+}
+
+TEST(CopySignTest, InDoubleRange) {
+  using BitsType = Properties::BitsType;
+  constexpr BitsType count = 1000000;
+  constexpr BitsType step = UINT64_MAX / count;
+  for (BitsType i = 0, v = 0; i <= count; ++i, v += step) {
+    double x = valueFromBits(v);
+    if (isnan(x) || isinf(x) || x == 0)
+      continue;
+
+    double res1 = __llvm_libc::copysign(x, -x);
+    ASSERT_TRUE(res1 == -x);
+
+    double res2 = __llvm_libc::copysign(x, x);
+    ASSERT_TRUE(res2 == x);
+  }
+}

diff  --git a/libc/test/src/math/copysignf_test.cpp b/libc/test/src/math/copysignf_test.cpp
new file mode 100644
index 000000000000..cb2cf518bde2
--- /dev/null
+++ b/libc/test/src/math/copysignf_test.cpp
@@ -0,0 +1,65 @@
+//===-- Unittests for copysignf
+//--------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "include/math.h"
+#include "src/math/copysignf.h"
+#include "utils/FPUtil/BitPatterns.h"
+#include "utils/FPUtil/FloatOperations.h"
+#include "utils/FPUtil/FloatProperties.h"
+#include "utils/UnitTest/Test.h"
+
+using __llvm_libc::fputil::valueAsBits;
+using __llvm_libc::fputil::valueFromBits;
+
+using BitPatterns = __llvm_libc::fputil::BitPatterns<float>;
+using Properties = __llvm_libc::fputil::FloatProperties<float>;
+
+TEST(CopySignFTest, SpecialNumbers) {
+  EXPECT_EQ(BitPatterns::aNegativeQuietNaN,
+            valueAsBits(__llvm_libc::copysignf(
+                valueFromBits(BitPatterns::aQuietNaN), -1.0f)));
+  EXPECT_EQ(BitPatterns::aQuietNaN,
+            valueAsBits(__llvm_libc::copysignf(
+                valueFromBits(BitPatterns::aNegativeQuietNaN), 1.0f)));
+
+  EXPECT_EQ(BitPatterns::aNegativeSignallingNaN,
+            valueAsBits(__llvm_libc::copysignf(
+                valueFromBits(BitPatterns::aSignallingNaN), -1.0f)));
+  EXPECT_EQ(BitPatterns::aSignallingNaN,
+            valueAsBits(__llvm_libc::copysignf(
+                valueFromBits(BitPatterns::aNegativeSignallingNaN), 1.0f)));
+
+  EXPECT_EQ(BitPatterns::negInf, valueAsBits(__llvm_libc::copysignf(
+                                     valueFromBits(BitPatterns::inf), -1.0f)));
+  EXPECT_EQ(BitPatterns::inf, valueAsBits(__llvm_libc::copysignf(
+                                  valueFromBits(BitPatterns::negInf), 1.0f)));
+
+  EXPECT_EQ(BitPatterns::negZero,
+            valueAsBits(__llvm_libc::copysignf(valueFromBits(BitPatterns::zero),
+                                               -1.0f)));
+  EXPECT_EQ(BitPatterns::zero, valueAsBits(__llvm_libc::copysignf(
+                                   valueFromBits(BitPatterns::negZero), 1.0f)));
+}
+
+TEST(CopySignFTest, InDoubleRange) {
+  using BitsType = Properties::BitsType;
+  constexpr BitsType count = 1000000;
+  constexpr BitsType step = UINT32_MAX / count;
+  for (BitsType i = 0, v = 0; i <= count; ++i, v += step) {
+    float x = valueFromBits(v);
+    if (isnan(x) || isinf(x) || x == 0)
+      continue;
+
+    float res1 = __llvm_libc::copysignf(x, -x);
+    ASSERT_TRUE(res1 == -x);
+
+    float res2 = __llvm_libc::copysignf(x, x);
+    ASSERT_TRUE(res2 == x);
+  }
+}

diff  --git a/libc/test/src/math/frexp_test.cpp b/libc/test/src/math/frexp_test.cpp
new file mode 100644
index 000000000000..a7fb953fb4fb
--- /dev/null
+++ b/libc/test/src/math/frexp_test.cpp
@@ -0,0 +1,141 @@
+//===-- Unittests for frexp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "include/math.h"
+#include "src/math/frexp.h"
+#include "utils/FPUtil/BitPatterns.h"
+#include "utils/FPUtil/FloatOperations.h"
+#include "utils/FPUtil/FloatProperties.h"
+#include "utils/UnitTest/Test.h"
+
+using __llvm_libc::fputil::valueAsBits;
+using __llvm_libc::fputil::valueFromBits;
+
+using BitPatterns = __llvm_libc::fputil::BitPatterns<double>;
+using Properties = __llvm_libc::fputil::FloatProperties<double>;
+
+TEST(FrexpTest, SpecialNumbers) {
+  int exponent;
+
+  EXPECT_EQ(BitPatterns::aQuietNaN,
+            valueAsBits(__llvm_libc::frexp(
+                valueFromBits(BitPatterns::aQuietNaN), &exponent)));
+  EXPECT_EQ(BitPatterns::aNegativeQuietNaN,
+            valueAsBits(__llvm_libc::frexp(
+                valueFromBits(BitPatterns::aNegativeQuietNaN), &exponent)));
+
+  EXPECT_EQ(BitPatterns::aSignallingNaN,
+            valueAsBits(__llvm_libc::frexp(
+                valueFromBits(BitPatterns::aSignallingNaN), &exponent)));
+  EXPECT_EQ(
+      BitPatterns::aNegativeSignallingNaN,
+      valueAsBits(__llvm_libc::frexp(
+          valueFromBits(BitPatterns::aNegativeSignallingNaN), &exponent)));
+
+  EXPECT_EQ(BitPatterns::inf, valueAsBits(__llvm_libc::frexp(
+                                  valueFromBits(BitPatterns::inf), &exponent)));
+  EXPECT_EQ(BitPatterns::negInf,
+            valueAsBits(__llvm_libc::frexp(valueFromBits(BitPatterns::negInf),
+                                           &exponent)));
+
+  EXPECT_EQ(BitPatterns::zero,
+            valueAsBits(__llvm_libc::frexp(valueFromBits(BitPatterns::zero),
+                                           &exponent)));
+  EXPECT_EQ(exponent, 0);
+  EXPECT_EQ(BitPatterns::negZero,
+            valueAsBits(__llvm_libc::frexp(valueFromBits(BitPatterns::negZero),
+                                           &exponent)));
+  EXPECT_EQ(exponent, 0);
+}
+
+TEST(FrexpTest, PowersOfTwo) {
+  int exponent;
+
+  EXPECT_EQ(valueAsBits(0.5), valueAsBits(__llvm_libc::frexp(1.0, &exponent)));
+  EXPECT_EQ(exponent, 1);
+  EXPECT_EQ(valueAsBits(-0.5),
+            valueAsBits(__llvm_libc::frexp(-1.0, &exponent)));
+  EXPECT_EQ(exponent, 1);
+
+  EXPECT_EQ(valueAsBits(0.5), valueAsBits(__llvm_libc::frexp(2.0, &exponent)));
+  EXPECT_EQ(exponent, 2);
+  EXPECT_EQ(valueAsBits(-0.5),
+            valueAsBits(__llvm_libc::frexp(-2.0, &exponent)));
+  EXPECT_EQ(exponent, 2);
+
+  EXPECT_EQ(valueAsBits(0.5), valueAsBits(__llvm_libc::frexp(4.0, &exponent)));
+  EXPECT_EQ(exponent, 3);
+  EXPECT_EQ(valueAsBits(-0.5),
+            valueAsBits(__llvm_libc::frexp(-4.0, &exponent)));
+  EXPECT_EQ(exponent, 3);
+
+  EXPECT_EQ(valueAsBits(0.5), valueAsBits(__llvm_libc::frexp(8.0, &exponent)));
+  EXPECT_EQ(exponent, 4);
+  EXPECT_EQ(valueAsBits(-0.5),
+            valueAsBits(__llvm_libc::frexp(-8.0, &exponent)));
+  EXPECT_EQ(exponent, 4);
+
+  EXPECT_EQ(valueAsBits(0.5), valueAsBits(__llvm_libc::frexp(16.0, &exponent)));
+  EXPECT_EQ(exponent, 5);
+  EXPECT_EQ(valueAsBits(-0.5),
+            valueAsBits(__llvm_libc::frexp(-16.0, &exponent)));
+  EXPECT_EQ(exponent, 5);
+
+  EXPECT_EQ(valueAsBits(0.5), valueAsBits(__llvm_libc::frexp(32.0, &exponent)));
+  EXPECT_EQ(exponent, 6);
+  EXPECT_EQ(valueAsBits(-0.5),
+            valueAsBits(__llvm_libc::frexp(-32.0, &exponent)));
+  EXPECT_EQ(exponent, 6);
+
+  EXPECT_EQ(valueAsBits(0.5), valueAsBits(__llvm_libc::frexp(64.0, &exponent)));
+  EXPECT_EQ(exponent, 7);
+  EXPECT_EQ(valueAsBits(-0.5),
+            valueAsBits(__llvm_libc::frexp(-64.0, &exponent)));
+  EXPECT_EQ(exponent, 7);
+}
+
+TEST(FrexpTest, SomeIntegers) {
+  int exponent;
+
+  EXPECT_EQ(valueAsBits(0.75),
+            valueAsBits(__llvm_libc::frexp(24.0, &exponent)));
+  EXPECT_EQ(exponent, 5);
+  EXPECT_EQ(valueAsBits(-0.75),
+            valueAsBits(__llvm_libc::frexp(-24.0, &exponent)));
+  EXPECT_EQ(exponent, 5);
+
+  EXPECT_EQ(valueAsBits(0.625),
+            valueAsBits(__llvm_libc::frexp(40.0, &exponent)));
+  EXPECT_EQ(exponent, 6);
+  EXPECT_EQ(valueAsBits(-0.625),
+            valueAsBits(__llvm_libc::frexp(-40.0, &exponent)));
+  EXPECT_EQ(exponent, 6);
+
+  EXPECT_EQ(valueAsBits(0.78125),
+            valueAsBits(__llvm_libc::frexp(800.0, &exponent)));
+  EXPECT_EQ(exponent, 10);
+  EXPECT_EQ(valueAsBits(-0.78125),
+            valueAsBits(__llvm_libc::frexp(-800.0, &exponent)));
+  EXPECT_EQ(exponent, 10);
+}
+
+TEST(FrexpTest, InDoubleRange) {
+  using BitsType = Properties::BitsType;
+  constexpr BitsType count = 1000000;
+  constexpr BitsType step = UINT64_MAX / count;
+  for (BitsType i = 0, v = 0; i <= count; ++i, v += step) {
+    double x = valueFromBits(v);
+    if (isnan(x) || isinf(x) || x == 0.0)
+      continue;
+    int exponent;
+    double frac = __llvm_libc::frexp(x, &exponent);
+
+    ASSERT_TRUE(__llvm_libc::fputil::abs(frac) < 1.0);
+    ASSERT_TRUE(__llvm_libc::fputil::abs(frac) >= 0.5);
+  }
+}

diff  --git a/libc/test/src/math/frexpf_test.cpp b/libc/test/src/math/frexpf_test.cpp
new file mode 100644
index 000000000000..d90532b63436
--- /dev/null
+++ b/libc/test/src/math/frexpf_test.cpp
@@ -0,0 +1,150 @@
+//===-- Unittests for frexpf
+//-----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "include/math.h"
+#include "src/math/frexpf.h"
+#include "utils/FPUtil/BitPatterns.h"
+#include "utils/FPUtil/FloatOperations.h"
+#include "utils/FPUtil/FloatProperties.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+#include "utils/UnitTest/Test.h"
+
+using __llvm_libc::fputil::valueAsBits;
+using __llvm_libc::fputil::valueFromBits;
+
+using BitPatterns = __llvm_libc::fputil::BitPatterns<float>;
+using Properties = __llvm_libc::fputil::FloatProperties<float>;
+
+TEST(FrexpfTest, SpecialNumbers) {
+  int exponent;
+
+  EXPECT_EQ(BitPatterns::aQuietNaN,
+            valueAsBits(__llvm_libc::frexpf(
+                valueFromBits(BitPatterns::aQuietNaN), &exponent)));
+  EXPECT_EQ(BitPatterns::aNegativeQuietNaN,
+            valueAsBits(__llvm_libc::frexpf(
+                valueFromBits(BitPatterns::aNegativeQuietNaN), &exponent)));
+
+  EXPECT_EQ(BitPatterns::aSignallingNaN,
+            valueAsBits(__llvm_libc::frexpf(
+                valueFromBits(BitPatterns::aSignallingNaN), &exponent)));
+  EXPECT_EQ(
+      BitPatterns::aNegativeSignallingNaN,
+      valueAsBits(__llvm_libc::frexpf(
+          valueFromBits(BitPatterns::aNegativeSignallingNaN), &exponent)));
+
+  EXPECT_EQ(BitPatterns::inf, valueAsBits(__llvm_libc::frexpf(
+                                  valueFromBits(BitPatterns::inf), &exponent)));
+  EXPECT_EQ(BitPatterns::negInf,
+            valueAsBits(__llvm_libc::frexpf(valueFromBits(BitPatterns::negInf),
+                                            &exponent)));
+
+  EXPECT_EQ(BitPatterns::zero,
+            valueAsBits(__llvm_libc::frexpf(valueFromBits(BitPatterns::zero),
+                                            &exponent)));
+  EXPECT_EQ(exponent, 0);
+  EXPECT_EQ(BitPatterns::negZero,
+            valueAsBits(__llvm_libc::frexpf(valueFromBits(BitPatterns::negZero),
+                                            &exponent)));
+  EXPECT_EQ(exponent, 0);
+}
+
+TEST(FrexpfTest, PowersOfTwo) {
+  int exponent;
+
+  EXPECT_EQ(valueAsBits(0.5f),
+            valueAsBits(__llvm_libc::frexpf(1.0f, &exponent)));
+  EXPECT_EQ(exponent, 1);
+  EXPECT_EQ(valueAsBits(-0.5f),
+            valueAsBits(__llvm_libc::frexpf(-1.0f, &exponent)));
+  EXPECT_EQ(exponent, 1);
+
+  EXPECT_EQ(valueAsBits(0.5f),
+            valueAsBits(__llvm_libc::frexpf(2.0f, &exponent)));
+  EXPECT_EQ(exponent, 2);
+  EXPECT_EQ(valueAsBits(-0.5f),
+            valueAsBits(__llvm_libc::frexpf(-2.0f, &exponent)));
+  EXPECT_EQ(exponent, 2);
+
+  EXPECT_EQ(valueAsBits(0.5f),
+            valueAsBits(__llvm_libc::frexpf(4.0f, &exponent)));
+  EXPECT_EQ(exponent, 3);
+  EXPECT_EQ(valueAsBits(-0.5f),
+            valueAsBits(__llvm_libc::frexpf(-4.0f, &exponent)));
+  EXPECT_EQ(exponent, 3);
+
+  EXPECT_EQ(valueAsBits(0.5f),
+            valueAsBits(__llvm_libc::frexpf(8.0f, &exponent)));
+  EXPECT_EQ(exponent, 4);
+  EXPECT_EQ(valueAsBits(-0.5f),
+            valueAsBits(__llvm_libc::frexpf(-8.0f, &exponent)));
+  EXPECT_EQ(exponent, 4);
+
+  EXPECT_EQ(valueAsBits(0.5f),
+            valueAsBits(__llvm_libc::frexpf(16.0f, &exponent)));
+  EXPECT_EQ(exponent, 5);
+  EXPECT_EQ(valueAsBits(-0.5f),
+            valueAsBits(__llvm_libc::frexpf(-16.0f, &exponent)));
+  EXPECT_EQ(exponent, 5);
+
+  EXPECT_EQ(valueAsBits(0.5f),
+            valueAsBits(__llvm_libc::frexpf(32.0f, &exponent)));
+  EXPECT_EQ(exponent, 6);
+  EXPECT_EQ(valueAsBits(-0.5f),
+            valueAsBits(__llvm_libc::frexpf(-32.0f, &exponent)));
+  EXPECT_EQ(exponent, 6);
+
+  EXPECT_EQ(valueAsBits(0.5f),
+            valueAsBits(__llvm_libc::frexpf(64.0f, &exponent)));
+  EXPECT_EQ(exponent, 7);
+  EXPECT_EQ(valueAsBits(-0.5f),
+            valueAsBits(__llvm_libc::frexpf(-64.0f, &exponent)));
+  EXPECT_EQ(exponent, 7);
+}
+
+TEST(FrexpTest, SomeIntegers) {
+  int exponent;
+
+  EXPECT_EQ(valueAsBits(0.75f),
+            valueAsBits(__llvm_libc::frexpf(24.0f, &exponent)));
+  EXPECT_EQ(exponent, 5);
+  EXPECT_EQ(valueAsBits(-0.75f),
+            valueAsBits(__llvm_libc::frexpf(-24.0f, &exponent)));
+  EXPECT_EQ(exponent, 5);
+
+  EXPECT_EQ(valueAsBits(0.625f),
+            valueAsBits(__llvm_libc::frexpf(40.0f, &exponent)));
+  EXPECT_EQ(exponent, 6);
+  EXPECT_EQ(valueAsBits(-0.625f),
+            valueAsBits(__llvm_libc::frexpf(-40.0f, &exponent)));
+  EXPECT_EQ(exponent, 6);
+
+  EXPECT_EQ(valueAsBits(0.78125f),
+            valueAsBits(__llvm_libc::frexpf(800.0f, &exponent)));
+  EXPECT_EQ(exponent, 10);
+  EXPECT_EQ(valueAsBits(-0.78125f),
+            valueAsBits(__llvm_libc::frexpf(-800.0f, &exponent)));
+  EXPECT_EQ(exponent, 10);
+}
+
+TEST(FrexpfTest, InFloatRange) {
+  using BitsType = Properties::BitsType;
+  constexpr BitsType count = 1000000;
+  constexpr BitsType step = UINT32_MAX / count;
+  for (BitsType i = 0, v = 0; i <= count; ++i, v += step) {
+    float x = valueFromBits(v);
+    if (isnan(x) || isinf(x) || x == 0.0)
+      continue;
+    int exponent;
+    float frac = __llvm_libc::frexpf(x, &exponent);
+
+    ASSERT_TRUE(__llvm_libc::fputil::abs(frac) < 1.0f);
+    ASSERT_TRUE(__llvm_libc::fputil::abs(frac) >= 0.5f);
+  }
+}

diff  --git a/libc/test/src/math/logb_test.cpp b/libc/test/src/math/logb_test.cpp
new file mode 100644
index 000000000000..5f8e75387489
--- /dev/null
+++ b/libc/test/src/math/logb_test.cpp
@@ -0,0 +1,99 @@
+//===-- Unittests for logb ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "include/math.h"
+#include "src/math/logb.h"
+#include "utils/FPUtil/BitPatterns.h"
+#include "utils/FPUtil/FloatOperations.h"
+#include "utils/FPUtil/FloatProperties.h"
+#include "utils/FPUtil/ManipulationFunctions.h"
+#include "utils/UnitTest/Test.h"
+
+using __llvm_libc::fputil::valueAsBits;
+using __llvm_libc::fputil::valueFromBits;
+
+using BitPatterns = __llvm_libc::fputil::BitPatterns<double>;
+using Properties = __llvm_libc::fputil::FloatProperties<double>;
+
+TEST(LogbTest, SpecialNumbers) {
+  EXPECT_EQ(
+      BitPatterns::aQuietNaN,
+      valueAsBits(__llvm_libc::logb(valueFromBits(BitPatterns::aQuietNaN))));
+  EXPECT_EQ(BitPatterns::aNegativeQuietNaN,
+            valueAsBits(__llvm_libc::logb(
+                valueFromBits(BitPatterns::aNegativeQuietNaN))));
+
+  EXPECT_EQ(BitPatterns::aSignallingNaN,
+            valueAsBits(
+                __llvm_libc::logb(valueFromBits(BitPatterns::aSignallingNaN))));
+  EXPECT_EQ(BitPatterns::aNegativeSignallingNaN,
+            valueAsBits(__llvm_libc::logb(
+                valueFromBits(BitPatterns::aNegativeSignallingNaN))));
+
+  EXPECT_EQ(BitPatterns::inf,
+            valueAsBits(__llvm_libc::logb(valueFromBits(BitPatterns::inf))));
+  EXPECT_EQ(BitPatterns::inf,
+            valueAsBits(__llvm_libc::logb(valueFromBits(BitPatterns::negInf))));
+
+  EXPECT_EQ(BitPatterns::negInf,
+            valueAsBits(__llvm_libc::logb(valueFromBits(BitPatterns::zero))));
+  EXPECT_EQ(BitPatterns::negInf, valueAsBits(__llvm_libc::logb(
+                                     valueFromBits(BitPatterns::negZero))));
+}
+
+TEST(LogbTest, PowersOfTwo) {
+  EXPECT_EQ(valueAsBits(0.0), valueAsBits(__llvm_libc::logb(1.0)));
+  EXPECT_EQ(valueAsBits(0.0), valueAsBits(__llvm_libc::logb(-1.0)));
+
+  EXPECT_EQ(valueAsBits(1.0), valueAsBits(__llvm_libc::logb(2.0)));
+  EXPECT_EQ(valueAsBits(1.0), valueAsBits(__llvm_libc::logb(-2.0)));
+
+  EXPECT_EQ(valueAsBits(2.0), valueAsBits(__llvm_libc::logb(4.0)));
+  EXPECT_EQ(valueAsBits(2.0), valueAsBits(__llvm_libc::logb(-4.0)));
+
+  EXPECT_EQ(valueAsBits(3.0), valueAsBits(__llvm_libc::logb(8.0)));
+  EXPECT_EQ(valueAsBits(3.0), valueAsBits(__llvm_libc::logb(-8.0)));
+
+  EXPECT_EQ(valueAsBits(4.0), valueAsBits(__llvm_libc::logb(16.0)));
+  EXPECT_EQ(valueAsBits(4.0), valueAsBits(__llvm_libc::logb(-16.0)));
+
+  EXPECT_EQ(valueAsBits(5.0), valueAsBits(__llvm_libc::logb(32.0)));
+  EXPECT_EQ(valueAsBits(5.0), valueAsBits(__llvm_libc::logb(-32.0)));
+}
+
+TEST(LogbTest, SomeIntegers) {
+  EXPECT_EQ(valueAsBits(1.0), valueAsBits(__llvm_libc::logb(3.0)));
+  EXPECT_EQ(valueAsBits(1.0), valueAsBits(__llvm_libc::logb(-3.0)));
+
+  EXPECT_EQ(valueAsBits(2.0), valueAsBits(__llvm_libc::logb(7.0)));
+  EXPECT_EQ(valueAsBits(2.0), valueAsBits(__llvm_libc::logb(-7.0)));
+
+  EXPECT_EQ(valueAsBits(3.0), valueAsBits(__llvm_libc::logb(10.0)));
+  EXPECT_EQ(valueAsBits(3.0), valueAsBits(__llvm_libc::logb(-10.0)));
+
+  EXPECT_EQ(valueAsBits(4.0), valueAsBits(__llvm_libc::logb(31.0)));
+  EXPECT_EQ(valueAsBits(4.0), valueAsBits(__llvm_libc::logb(-31.0)));
+
+  EXPECT_EQ(valueAsBits(5.0), valueAsBits(__llvm_libc::logb(55.0)));
+  EXPECT_EQ(valueAsBits(5.0), valueAsBits(__llvm_libc::logb(-55.0)));
+}
+
+TEST(LogbTest, InDoubleRange) {
+  using BitsType = Properties::BitsType;
+  constexpr BitsType count = 10000000;
+  constexpr BitsType step = UINT64_MAX / count;
+  for (BitsType i = 0, v = 0; i <= count; ++i, v += step) {
+    double x = valueFromBits(v);
+    if (isnan(x) || isinf(x) || x == 0.0)
+      continue;
+
+    int exponent;
+    __llvm_libc::fputil::frexp(x, exponent);
+    ASSERT_TRUE(double(exponent) == __llvm_libc::logb(x) + 1.0);
+  }
+}

diff  --git a/libc/test/src/math/logbf_test.cpp b/libc/test/src/math/logbf_test.cpp
new file mode 100644
index 000000000000..7cd690ce3869
--- /dev/null
+++ b/libc/test/src/math/logbf_test.cpp
@@ -0,0 +1,99 @@
+//===-- Unittests for logbf -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "include/math.h"
+#include "src/math/logbf.h"
+#include "utils/FPUtil/BitPatterns.h"
+#include "utils/FPUtil/FloatOperations.h"
+#include "utils/FPUtil/FloatProperties.h"
+#include "utils/FPUtil/ManipulationFunctions.h"
+#include "utils/UnitTest/Test.h"
+
+using __llvm_libc::fputil::valueAsBits;
+using __llvm_libc::fputil::valueFromBits;
+
+using BitPatterns = __llvm_libc::fputil::BitPatterns<float>;
+using Properties = __llvm_libc::fputil::FloatProperties<float>;
+
+TEST(LogbfTest, SpecialNumbers) {
+  EXPECT_EQ(
+      BitPatterns::aQuietNaN,
+      valueAsBits(__llvm_libc::logbf(valueFromBits(BitPatterns::aQuietNaN))));
+  EXPECT_EQ(BitPatterns::aNegativeQuietNaN,
+            valueAsBits(__llvm_libc::logbf(
+                valueFromBits(BitPatterns::aNegativeQuietNaN))));
+
+  EXPECT_EQ(BitPatterns::aSignallingNaN,
+            valueAsBits(__llvm_libc::logbf(
+                valueFromBits(BitPatterns::aSignallingNaN))));
+  EXPECT_EQ(BitPatterns::aNegativeSignallingNaN,
+            valueAsBits(__llvm_libc::logbf(
+                valueFromBits(BitPatterns::aNegativeSignallingNaN))));
+
+  EXPECT_EQ(BitPatterns::inf,
+            valueAsBits(__llvm_libc::logbf(valueFromBits(BitPatterns::inf))));
+  EXPECT_EQ(BitPatterns::inf, valueAsBits(__llvm_libc::logbf(
+                                  valueFromBits(BitPatterns::negInf))));
+
+  EXPECT_EQ(BitPatterns::negInf,
+            valueAsBits(__llvm_libc::logbf(valueFromBits(BitPatterns::zero))));
+  EXPECT_EQ(BitPatterns::negInf, valueAsBits(__llvm_libc::logbf(
+                                     valueFromBits(BitPatterns::negZero))));
+}
+
+TEST(LogbfTest, PowersOfTwo) {
+  EXPECT_EQ(valueAsBits(0.0f), valueAsBits(__llvm_libc::logbf(1.0f)));
+  EXPECT_EQ(valueAsBits(0.0f), valueAsBits(__llvm_libc::logbf(-1.0f)));
+
+  EXPECT_EQ(valueAsBits(1.0f), valueAsBits(__llvm_libc::logbf(2.0f)));
+  EXPECT_EQ(valueAsBits(1.0f), valueAsBits(__llvm_libc::logbf(-2.0f)));
+
+  EXPECT_EQ(valueAsBits(2.0f), valueAsBits(__llvm_libc::logbf(4.0f)));
+  EXPECT_EQ(valueAsBits(2.0f), valueAsBits(__llvm_libc::logbf(-4.0f)));
+
+  EXPECT_EQ(valueAsBits(3.0f), valueAsBits(__llvm_libc::logbf(8.0f)));
+  EXPECT_EQ(valueAsBits(3.0f), valueAsBits(__llvm_libc::logbf(-8.0f)));
+
+  EXPECT_EQ(valueAsBits(4.0f), valueAsBits(__llvm_libc::logbf(16.0f)));
+  EXPECT_EQ(valueAsBits(4.0f), valueAsBits(__llvm_libc::logbf(-16.0f)));
+
+  EXPECT_EQ(valueAsBits(5.0f), valueAsBits(__llvm_libc::logbf(32.0f)));
+  EXPECT_EQ(valueAsBits(5.0f), valueAsBits(__llvm_libc::logbf(-32.0f)));
+}
+
+TEST(LogbTest, SomeIntegers) {
+  EXPECT_EQ(valueAsBits(1.0f), valueAsBits(__llvm_libc::logbf(3.0f)));
+  EXPECT_EQ(valueAsBits(1.0f), valueAsBits(__llvm_libc::logbf(-3.0f)));
+
+  EXPECT_EQ(valueAsBits(2.0f), valueAsBits(__llvm_libc::logbf(7.0f)));
+  EXPECT_EQ(valueAsBits(2.0f), valueAsBits(__llvm_libc::logbf(-7.0f)));
+
+  EXPECT_EQ(valueAsBits(3.0f), valueAsBits(__llvm_libc::logbf(10.0f)));
+  EXPECT_EQ(valueAsBits(3.0f), valueAsBits(__llvm_libc::logbf(-10.0f)));
+
+  EXPECT_EQ(valueAsBits(4.0f), valueAsBits(__llvm_libc::logbf(31.0f)));
+  EXPECT_EQ(valueAsBits(4.0f), valueAsBits(__llvm_libc::logbf(-31.0f)));
+
+  EXPECT_EQ(valueAsBits(5.0f), valueAsBits(__llvm_libc::logbf(55.0f)));
+  EXPECT_EQ(valueAsBits(5.0f), valueAsBits(__llvm_libc::logbf(-55.0f)));
+}
+
+TEST(LogbfTest, InDoubleRange) {
+  using BitsType = Properties::BitsType;
+  constexpr BitsType count = 10000000;
+  constexpr BitsType step = UINT32_MAX / count;
+  for (BitsType i = 0, v = 0; i <= count; ++i, v += step) {
+    float x = valueFromBits(v);
+    if (isnan(x) || isinf(x) || x == 0.0)
+      continue;
+
+    int exponent;
+    __llvm_libc::fputil::frexp(x, exponent);
+    ASSERT_TRUE(float(exponent) == __llvm_libc::logbf(x) + 1.0);
+  }
+}

diff  --git a/libc/test/src/math/modf_test.cpp b/libc/test/src/math/modf_test.cpp
new file mode 100644
index 000000000000..fa4436d64151
--- /dev/null
+++ b/libc/test/src/math/modf_test.cpp
@@ -0,0 +1,130 @@
+//===-- Unittests for modf ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "include/math.h"
+#include "src/math/modf.h"
+#include "utils/FPUtil/BitPatterns.h"
+#include "utils/FPUtil/FloatOperations.h"
+#include "utils/FPUtil/FloatProperties.h"
+#include "utils/UnitTest/Test.h"
+
+using __llvm_libc::fputil::valueAsBits;
+using __llvm_libc::fputil::valueFromBits;
+
+using BitPatterns = __llvm_libc::fputil::BitPatterns<double>;
+using Properties = __llvm_libc::fputil::FloatProperties<double>;
+
+TEST(ModfTest, SpecialNumbers) {
+  double integral;
+
+  EXPECT_EQ(BitPatterns::aQuietNaN,
+            valueAsBits(__llvm_libc::modf(valueFromBits(BitPatterns::aQuietNaN),
+                                          &integral)));
+  EXPECT_EQ(BitPatterns::aNegativeQuietNaN,
+            valueAsBits(__llvm_libc::modf(
+                valueFromBits(BitPatterns::aNegativeQuietNaN), &integral)));
+
+  EXPECT_EQ(BitPatterns::aSignallingNaN,
+            valueAsBits(__llvm_libc::modf(
+                valueFromBits(BitPatterns::aSignallingNaN), &integral)));
+  EXPECT_EQ(
+      BitPatterns::aNegativeSignallingNaN,
+      valueAsBits(__llvm_libc::modf(
+          valueFromBits(BitPatterns::aNegativeSignallingNaN), &integral)));
+
+  EXPECT_EQ(BitPatterns::zero,
+            valueAsBits(
+                __llvm_libc::modf(valueFromBits(BitPatterns::inf), &integral)));
+  EXPECT_EQ(valueAsBits(integral), BitPatterns::inf);
+
+  EXPECT_EQ(BitPatterns::negZero,
+            valueAsBits(__llvm_libc::modf(valueFromBits(BitPatterns::negInf),
+                                          &integral)));
+  EXPECT_EQ(valueAsBits(integral), BitPatterns::negInf);
+
+  EXPECT_EQ(BitPatterns::zero,
+            valueAsBits(__llvm_libc::modf(valueFromBits(BitPatterns::zero),
+                                          &integral)));
+  EXPECT_EQ(valueAsBits(integral), BitPatterns::zero);
+
+  EXPECT_EQ(BitPatterns::negZero,
+            valueAsBits(__llvm_libc::modf(valueFromBits(BitPatterns::negZero),
+                                          &integral)));
+  EXPECT_EQ(valueAsBits(integral), BitPatterns::negZero);
+}
+
+TEST(ModfTest, Integers) {
+  double integral;
+
+  EXPECT_EQ(BitPatterns::zero, valueAsBits(__llvm_libc::modf(1.0, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(1.0));
+
+  EXPECT_EQ(BitPatterns::negZero,
+            valueAsBits(__llvm_libc::modf(-1.0, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(-1.0));
+
+  EXPECT_EQ(BitPatterns::zero, valueAsBits(__llvm_libc::modf(10.0, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(10.0));
+
+  EXPECT_EQ(BitPatterns::negZero,
+            valueAsBits(__llvm_libc::modf(-10.0, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(-10.0));
+
+  EXPECT_EQ(BitPatterns::zero,
+            valueAsBits(__llvm_libc::modf(12345.0, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(12345.0));
+
+  EXPECT_EQ(BitPatterns::negZero,
+            valueAsBits(__llvm_libc::modf(-12345.0, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(-12345.0));
+}
+
+TEST(ModfTest, Fractions) {
+  double integral;
+
+  EXPECT_EQ(valueAsBits(0.5), valueAsBits(__llvm_libc::modf(1.5, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(1.0));
+
+  EXPECT_EQ(valueAsBits(-0.5), valueAsBits(__llvm_libc::modf(-1.5, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(-1.0));
+
+  EXPECT_EQ(valueAsBits(0.75),
+            valueAsBits(__llvm_libc::modf(10.75, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(10.0));
+
+  EXPECT_EQ(valueAsBits(-0.75),
+            valueAsBits(__llvm_libc::modf(-10.75, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(-10.0));
+
+  EXPECT_EQ(valueAsBits(0.125),
+            valueAsBits(__llvm_libc::modf(100.125, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(100.0));
+
+  EXPECT_EQ(valueAsBits(-0.125),
+            valueAsBits(__llvm_libc::modf(-100.125, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(-100.0));
+}
+
+TEST(ModfTest, InDoubleRange) {
+  using BitsType = Properties::BitsType;
+  constexpr BitsType count = 10000000;
+  constexpr BitsType step = UINT64_MAX / count;
+  for (BitsType i = 0, v = 0; i <= count; ++i, v += step) {
+    double x = valueFromBits(v);
+    if (isnan(x) || isinf(x) || x == 0.0) {
+      // These conditions have been tested in other tests.
+      continue;
+    }
+
+    double integral;
+    double frac = __llvm_libc::modf(x, &integral);
+    ASSERT_TRUE(__llvm_libc::fputil::abs(frac) < 1.0);
+    ASSERT_TRUE(__llvm_libc::fputil::trunc(x) == integral);
+    ASSERT_TRUE(integral + frac == x);
+  }
+}

diff  --git a/libc/test/src/math/modff_test.cpp b/libc/test/src/math/modff_test.cpp
new file mode 100644
index 000000000000..db3b7c801212
--- /dev/null
+++ b/libc/test/src/math/modff_test.cpp
@@ -0,0 +1,135 @@
+//===-- Unittests for modfff
+//-----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "include/math.h"
+#include "src/math/modff.h"
+#include "utils/FPUtil/BitPatterns.h"
+#include "utils/FPUtil/FloatOperations.h"
+#include "utils/FPUtil/FloatProperties.h"
+#include "utils/UnitTest/Test.h"
+
+using __llvm_libc::fputil::valueAsBits;
+using __llvm_libc::fputil::valueFromBits;
+
+using BitPatterns = __llvm_libc::fputil::BitPatterns<float>;
+using Properties = __llvm_libc::fputil::FloatProperties<float>;
+
+TEST(ModffTest, SpecialNumbers) {
+  float integral;
+
+  EXPECT_EQ(BitPatterns::aQuietNaN,
+            valueAsBits(__llvm_libc::modff(
+                valueFromBits(BitPatterns::aQuietNaN), &integral)));
+  EXPECT_EQ(BitPatterns::aNegativeQuietNaN,
+            valueAsBits(__llvm_libc::modff(
+                valueFromBits(BitPatterns::aNegativeQuietNaN), &integral)));
+
+  EXPECT_EQ(BitPatterns::aSignallingNaN,
+            valueAsBits(__llvm_libc::modff(
+                valueFromBits(BitPatterns::aSignallingNaN), &integral)));
+  EXPECT_EQ(
+      BitPatterns::aNegativeSignallingNaN,
+      valueAsBits(__llvm_libc::modff(
+          valueFromBits(BitPatterns::aNegativeSignallingNaN), &integral)));
+
+  EXPECT_EQ(BitPatterns::zero,
+            valueAsBits(__llvm_libc::modff(valueFromBits(BitPatterns::inf),
+                                           &integral)));
+  EXPECT_EQ(valueAsBits(integral), BitPatterns::inf);
+
+  EXPECT_EQ(BitPatterns::negZero,
+            valueAsBits(__llvm_libc::modff(valueFromBits(BitPatterns::negInf),
+                                           &integral)));
+  EXPECT_EQ(valueAsBits(integral), BitPatterns::negInf);
+
+  EXPECT_EQ(BitPatterns::zero,
+            valueAsBits(__llvm_libc::modff(valueFromBits(BitPatterns::zero),
+                                           &integral)));
+  EXPECT_EQ(valueAsBits(integral), BitPatterns::zero);
+
+  EXPECT_EQ(BitPatterns::negZero,
+            valueAsBits(__llvm_libc::modff(valueFromBits(BitPatterns::negZero),
+                                           &integral)));
+  EXPECT_EQ(valueAsBits(integral), BitPatterns::negZero);
+}
+
+TEST(ModffTest, Integers) {
+  float integral;
+
+  EXPECT_EQ(BitPatterns::zero,
+            valueAsBits(__llvm_libc::modff(1.0f, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(1.0f));
+
+  EXPECT_EQ(BitPatterns::negZero,
+            valueAsBits(__llvm_libc::modff(-1.0f, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(-1.0f));
+
+  EXPECT_EQ(BitPatterns::zero,
+            valueAsBits(__llvm_libc::modff(10.0f, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(10.0f));
+
+  EXPECT_EQ(BitPatterns::negZero,
+            valueAsBits(__llvm_libc::modff(-10.0f, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(-10.0f));
+
+  EXPECT_EQ(BitPatterns::zero,
+            valueAsBits(__llvm_libc::modff(12345.0f, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(12345.0f));
+
+  EXPECT_EQ(BitPatterns::negZero,
+            valueAsBits(__llvm_libc::modff(-12345.0f, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(-12345.0f));
+}
+
+TEST(ModfTest, Fractions) {
+  float integral;
+
+  EXPECT_EQ(valueAsBits(0.5f),
+            valueAsBits(__llvm_libc::modff(1.5f, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(1.0f));
+
+  EXPECT_EQ(valueAsBits(-0.5f),
+            valueAsBits(__llvm_libc::modff(-1.5f, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(-1.0f));
+
+  EXPECT_EQ(valueAsBits(0.75f),
+            valueAsBits(__llvm_libc::modff(10.75f, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(10.0f));
+
+  EXPECT_EQ(valueAsBits(-0.75f),
+            valueAsBits(__llvm_libc::modff(-10.75f, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(-10.0f));
+
+  EXPECT_EQ(valueAsBits(0.125f),
+            valueAsBits(__llvm_libc::modff(100.125f, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(100.0f));
+
+  EXPECT_EQ(valueAsBits(-0.125f),
+            valueAsBits(__llvm_libc::modff(-100.125f, &integral)));
+  EXPECT_EQ(valueAsBits(integral), valueAsBits(-100.0f));
+}
+
+TEST(ModffTest, InDoubleRange) {
+  using BitsType = Properties::BitsType;
+  constexpr BitsType count = 10000000;
+  constexpr BitsType step = UINT32_MAX / count;
+  for (BitsType i = 0, v = 0; i <= count; ++i, v += step) {
+    float x = valueFromBits(v);
+    if (isnan(x) || isinf(x) || x == 0.0f) {
+      // These conditions have been tested in other tests.
+      continue;
+    }
+
+    float integral;
+    float frac = __llvm_libc::modff(x, &integral);
+    ASSERT_TRUE(__llvm_libc::fputil::abs(frac) < 1.0f);
+    ASSERT_TRUE(__llvm_libc::fputil::trunc(x) == integral);
+    ASSERT_TRUE(integral + frac == x);
+  }
+}

diff  --git a/libc/utils/FPUtil/BitPatterns.h b/libc/utils/FPUtil/BitPatterns.h
index 35c58a43d906..439ccbcdcb92 100644
--- a/libc/utils/FPUtil/BitPatterns.h
+++ b/libc/utils/FPUtil/BitPatterns.h
@@ -11,6 +11,12 @@
 
 #include "FloatProperties.h"
 
+#include <float.h>
+
+static_assert(
+    FLT_RADIX == 2,
+    "LLVM libc only supports radix 2 IEEE 754 floating point formats.");
+
 namespace __llvm_libc {
 namespace fputil {
 

diff  --git a/libc/utils/FPUtil/CMakeLists.txt b/libc/utils/FPUtil/CMakeLists.txt
index b50ede179fcf..21013ee1771f 100644
--- a/libc/utils/FPUtil/CMakeLists.txt
+++ b/libc/utils/FPUtil/CMakeLists.txt
@@ -4,6 +4,7 @@ add_header_library(
     BitPatterns.h
     FloatOperations.h
     FloatProperties.h
+    ManipulationFunctions.h
   DEPS
     libc.utils.CPP.standalone_cpp
 )

diff  --git a/libc/utils/FPUtil/FloatOperations.h b/libc/utils/FPUtil/FloatOperations.h
index d841237176a5..b599aad37f41 100644
--- a/libc/utils/FPUtil/FloatOperations.h
+++ b/libc/utils/FPUtil/FloatOperations.h
@@ -57,26 +57,30 @@ static inline int getExponent(T x) {
   return getExponentFromBits(valueAsBits(x));
 }
 
+template <typename BitsType> static inline bool bitsAreInf(BitsType bits) {
+  using FPType = typename FloatType<BitsType>::Type;
+  return ((bits & BitPatterns<FPType>::inf) == BitPatterns<FPType>::inf) &&
+         ((bits & FloatProperties<FPType>::mantissaMask) == 0);
+}
+
 // Return true if x is infinity (positive or negative.)
 template <typename T,
           cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
 static inline bool isInf(T x) {
-  using Properties = FloatProperties<T>;
-  using BitsType = typename FloatProperties<T>::BitsType;
-  BitsType bits = valueAsBits(x);
-  return ((bits & BitPatterns<T>::inf) == BitPatterns<T>::inf) &&
-         ((bits & Properties::mantissaMask) == 0);
+  return bitsAreInf(valueAsBits(x));
+}
+
+template <typename BitsType> static inline bool bitsAreNaN(BitsType bits) {
+  using FPType = typename FloatType<BitsType>::Type;
+  return ((bits & BitPatterns<FPType>::inf) == BitPatterns<FPType>::inf) &&
+         ((bits & FloatProperties<FPType>::mantissaMask) != 0);
 }
 
 // Return true if x is a NAN (quiet or signalling.)
 template <typename T,
           cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
 static inline bool isNaN(T x) {
-  using Properties = FloatProperties<T>;
-  using BitsType = typename FloatProperties<T>::BitsType;
-  BitsType bits = valueAsBits(x);
-  return ((bits & BitPatterns<T>::inf) == BitPatterns<T>::inf) &&
-         ((bits & Properties::mantissaMask) != 0);
+  return bitsAreNaN(valueAsBits(x));
 }
 
 template <typename BitsType> static inline bool bitsAreInfOrNaN(BitsType bits) {

diff  --git a/libc/utils/FPUtil/ManipulationFunctions.h b/libc/utils/FPUtil/ManipulationFunctions.h
new file mode 100644
index 000000000000..a59c0a7e4cf9
--- /dev/null
+++ b/libc/utils/FPUtil/ManipulationFunctions.h
@@ -0,0 +1,102 @@
+//===-- Common operations on floating point numbers -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "BitPatterns.h"
+#include "FloatOperations.h"
+#include "FloatProperties.h"
+
+#include "utils/CPP/TypeTraits.h"
+
+#ifndef LLVM_LIBC_UTILS_FPUTIL_MANIPULATION_FUNCTIONS_H
+#define LLVM_LIBC_UTILS_FPUTIL_MANIPULATION_FUNCTIONS_H
+
+namespace __llvm_libc {
+namespace fputil {
+
+template <typename T,
+          cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
+static inline T frexp(T x, int &exp) {
+  using Properties = FloatProperties<T>;
+  using BitsType = typename Properties::BitsType;
+
+  auto bits = valueAsBits(x);
+  if (bitsAreInfOrNaN(bits))
+    return x;
+  if (bitsAreZero(bits)) {
+    exp = 0;
+    return x;
+  }
+
+  exp = getExponentFromBits(bits) + 1;
+
+  static constexpr BitsType resultExponent =
+      Properties::exponentOffset - BitsType(1);
+  // Capture the sign and mantissa part.
+  bits &= (Properties::mantissaMask | Properties::signMask);
+  // Insert the new exponent.
+  bits |= (resultExponent << Properties::mantissaWidth);
+
+  return valueFromBits(bits);
+}
+
+template <typename T,
+          cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
+static inline T modf(T x, T &iptr) {
+  auto bits = valueAsBits(x);
+  if (bitsAreZero(bits) || bitsAreNaN(bits)) {
+    iptr = x;
+    return x;
+  } else if (bitsAreInf(bits)) {
+    iptr = x;
+    return bits & FloatProperties<T>::signMask
+               ? valueFromBits(BitPatterns<T>::negZero)
+               : valueFromBits(BitPatterns<T>::zero);
+  } else {
+    iptr = trunc(x);
+    if (x == iptr) {
+      // If x is already an integer value, then return zero with the right
+      // sign.
+      return bits & FloatProperties<T>::signMask
+                 ? valueFromBits(BitPatterns<T>::negZero)
+                 : valueFromBits(BitPatterns<T>::zero);
+    } else {
+      return x - iptr;
+    }
+  }
+}
+
+template <typename T,
+          cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
+static inline T copysign(T x, T y) {
+  constexpr auto signMask = FloatProperties<T>::signMask;
+  auto xbits = valueAsBits(x);
+  auto ybits = valueAsBits(y);
+  return valueFromBits((xbits & ~signMask) | (ybits & signMask));
+}
+
+template <typename T,
+          cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
+static inline T logb(T x) {
+  auto bits = valueAsBits(x);
+  if (bitsAreZero(bits)) {
+    // TODO(Floating point exception): Raise div-by-zero exception.
+    // TODO(errno): POSIX requires setting errno to ERANGE.
+    return valueFromBits(BitPatterns<T>::negInf);
+  } else if (bitsAreInf(bits)) {
+    return valueFromBits(BitPatterns<T>::inf);
+  } else if (bitsAreNaN(bits)) {
+    return x;
+  } else {
+    return getExponentFromBits(bits);
+  }
+}
+
+} // namespace fputil
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_UTILS_FPUTIL_MANIPULATION_FUNCTIONS_H


        


More information about the libc-commits mailing list