Merge pull request rust-lang/libm#160 from rust-lang-nursery/azure-pipelines
Set up CI with Azure Pipelines
This commit is contained in:
commit
ba10db1ae5
112 changed files with 736 additions and 1530 deletions
|
|
@ -1,58 +0,0 @@
|
|||
language: rust
|
||||
services: docker
|
||||
sudo: required
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- env: TARGET=aarch64-unknown-linux-gnu
|
||||
rust: nightly
|
||||
- env: TARGET=armv7-unknown-linux-gnueabihf
|
||||
rust: nightly
|
||||
- env: TARGET=i686-unknown-linux-gnu
|
||||
rust: nightly
|
||||
- env: TARGET=mips-unknown-linux-gnu
|
||||
rust: nightly
|
||||
- env: TARGET=mips64-unknown-linux-gnuabi64
|
||||
rust: nightly
|
||||
- env: TARGET=mips64el-unknown-linux-gnuabi64
|
||||
rust: nightly
|
||||
- env: TARGET=mipsel-unknown-linux-gnu
|
||||
rust: nightly
|
||||
- env: TARGET=powerpc-unknown-linux-gnu
|
||||
rust: nightly
|
||||
- env: TARGET=powerpc64-unknown-linux-gnu
|
||||
rust: nightly
|
||||
- env: TARGET=powerpc64le-unknown-linux-gnu
|
||||
rust: nightly
|
||||
- env: TARGET=x86_64-unknown-linux-gnu
|
||||
rust: nightly
|
||||
- env: TARGET=cargo-fmt
|
||||
rust: beta
|
||||
|
||||
- env: TARGET=wasm32-unknown-unknown
|
||||
rust: nightly
|
||||
install: rustup target add $TARGET
|
||||
script:
|
||||
- cargo build --target $TARGET
|
||||
- cargo build --no-default-features --target $TARGET
|
||||
|
||||
before_install: set -e
|
||||
|
||||
install:
|
||||
- bash ci/install.sh
|
||||
|
||||
script:
|
||||
- export PATH=$HOME/.local/bin:$PATH
|
||||
- bash ci/script.sh
|
||||
|
||||
after_script: set +e
|
||||
|
||||
cache: cargo
|
||||
|
||||
before_cache:
|
||||
- chmod -R a+r $HOME/.cargo;
|
||||
|
||||
branches:
|
||||
only:
|
||||
- staging
|
||||
- trying
|
||||
|
|
@ -6,23 +6,30 @@ documentation = "https://docs.rs/libm"
|
|||
keywords = ["libm", "math"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
name = "libm"
|
||||
repository = "https://github.com/japaric/libm"
|
||||
repository = "https://github.com/rust-lang-nursery/libm"
|
||||
version = "0.1.2"
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
# only used to run our test suite
|
||||
checked = []
|
||||
default = ['stable']
|
||||
stable = []
|
||||
|
||||
# Generate tests which are random inputs and the outputs are calculated with
|
||||
# musl libc.
|
||||
musl-reference-tests = ['rand']
|
||||
|
||||
# Used checked array indexing instead of unchecked array indexing in this
|
||||
# library.
|
||||
checked = []
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"cb",
|
||||
"input-generator",
|
||||
"musl-generator",
|
||||
"newlib-generator",
|
||||
"shared",
|
||||
"crates/compiler-builtins-smoke-test",
|
||||
]
|
||||
|
||||
[dev-dependencies]
|
||||
shared = { path = "shared" }
|
||||
no-panic = "0.1.8"
|
||||
|
||||
[build-dependencies]
|
||||
rand = { version = "0.6.5", optional = true }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
# `libm`
|
||||
|
||||
[](https://dev.azure.com/rust-lang/libm/_build/latest?definitionId=7&branchName=master)
|
||||
|
||||
A port of [MUSL]'s libm to Rust.
|
||||
|
||||
[MUSL]: https://www.musl-libc.org/
|
||||
|
|
|
|||
73
library/compiler-builtins/libm/azure-pipelines.yml
Normal file
73
library/compiler-builtins/libm/azure-pipelines.yml
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
trigger:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
- job: Docker
|
||||
pool:
|
||||
vmImage: ubuntu-16.04
|
||||
steps:
|
||||
- template: ci/azure-install-rust.yml
|
||||
- bash: rustup target add $TARGET
|
||||
displayName: "add cross target"
|
||||
- bash: rustup target add x86_64-unknown-linux-musl
|
||||
displayName: "add musl target"
|
||||
- bash: cargo generate-lockfile && ./ci/run-docker.sh $TARGET
|
||||
displayName: "run tests"
|
||||
strategy:
|
||||
matrix:
|
||||
aarch64:
|
||||
TARGET: aarch64-unknown-linux-gnu
|
||||
arm:
|
||||
TARGET: arm-unknown-linux-gnueabi
|
||||
armhf:
|
||||
TARGET: arm-unknown-linux-gnueabihf
|
||||
armv7:
|
||||
TARGET: armv7-unknown-linux-gnueabihf
|
||||
i686:
|
||||
TARGET: i686-unknown-linux-gnu
|
||||
mips:
|
||||
TARGET: mips-unknown-linux-gnu
|
||||
mips64:
|
||||
TARGET: mips64-unknown-linux-gnuabi64
|
||||
mips64el:
|
||||
TARGET: mips64el-unknown-linux-gnuabi64
|
||||
powerpc:
|
||||
TARGET: powerpc-unknown-linux-gnu
|
||||
powerpc64:
|
||||
TARGET: powerpc64-unknown-linux-gnu
|
||||
powerpc64le:
|
||||
TARGET: powerpc64le-unknown-linux-gnu
|
||||
x86_64:
|
||||
TARGET: x86_64-unknown-linux-gnu
|
||||
|
||||
- job: wasm
|
||||
pool:
|
||||
vmImage: ubuntu-16.04
|
||||
steps:
|
||||
- template: ci/azure-install-rust.yml
|
||||
- script: rustup target add wasm32-unknown-unknown
|
||||
displayName: "Install rust wasm target"
|
||||
- script: cargo build --target wasm32-unknown-unknown
|
||||
displayName: "Build for wasm"
|
||||
- script: cargo build --target wasm32-unknown-unknown --no-default-features
|
||||
displayName: "Build for wasm (no default features)"
|
||||
variables:
|
||||
TOOLCHAIN: nightly
|
||||
|
||||
- job: rustfmt
|
||||
pool:
|
||||
vmImage: ubuntu-16.04
|
||||
steps:
|
||||
- template: ci/azure-install-rust.yml
|
||||
- bash: rustup component add rustfmt
|
||||
displayName: "install rustfmt"
|
||||
- bash: cargo fmt --all -- --check
|
||||
displayName: "check formatting"
|
||||
|
||||
- job: compiler_builtins_works
|
||||
pool:
|
||||
vmImage: ubuntu-16.04
|
||||
steps:
|
||||
- template: ci/azure-install-rust.yml
|
||||
- bash: cargo build -p cb
|
||||
displayName: "Check compiler-builtins still probably builds"
|
||||
353
library/compiler-builtins/libm/build.rs
Normal file
353
library/compiler-builtins/libm/build.rs
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
use std::env;
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
#[cfg(feature = "musl-reference-tests")]
|
||||
musl_reference_tests::generate();
|
||||
|
||||
if !cfg!(feature = "checked") {
|
||||
let lvl = env::var("OPT_LEVEL").unwrap();
|
||||
if lvl != "0" {
|
||||
println!("cargo:rustc-cfg=assert_no_panic");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "musl-reference-tests")]
|
||||
mod musl_reference_tests {
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::Rng;
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
|
||||
// Number of tests to generate for each function
|
||||
const NTESTS: usize = 500;
|
||||
|
||||
// These files are all internal functions or otherwise miscellaneous, not
|
||||
// defining a function we want to test.
|
||||
const IGNORED_FILES: &[&str] = &[
|
||||
"expo2.rs",
|
||||
"fenv.rs",
|
||||
"k_cos.rs",
|
||||
"k_cosf.rs",
|
||||
"k_expo2.rs",
|
||||
"k_expo2f.rs",
|
||||
"k_sin.rs",
|
||||
"k_sinf.rs",
|
||||
"k_tan.rs",
|
||||
"k_tanf.rs",
|
||||
"mod.rs",
|
||||
"rem_pio2.rs",
|
||||
"rem_pio2_large.rs",
|
||||
"rem_pio2f.rs",
|
||||
];
|
||||
|
||||
struct Function {
|
||||
name: String,
|
||||
args: Vec<Ty>,
|
||||
ret: Ty,
|
||||
tests: Vec<Test>,
|
||||
}
|
||||
|
||||
enum Ty {
|
||||
F32,
|
||||
F64,
|
||||
I32,
|
||||
Bool,
|
||||
}
|
||||
|
||||
struct Test {
|
||||
inputs: Vec<i64>,
|
||||
output: i64,
|
||||
}
|
||||
|
||||
pub fn generate() {
|
||||
let files = fs::read_dir("src/math")
|
||||
.unwrap()
|
||||
.map(|f| f.unwrap().path())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut math = Vec::new();
|
||||
for file in files {
|
||||
if IGNORED_FILES.iter().any(|f| file.ends_with(f)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
println!("generating musl reference tests in {:?}", file);
|
||||
|
||||
let contents = fs::read_to_string(file).unwrap();
|
||||
let mut functions = contents.lines().filter(|f| f.starts_with("pub fn"));
|
||||
let function_to_test = functions.next().unwrap();
|
||||
if functions.next().is_some() {
|
||||
panic!("more than one function in");
|
||||
}
|
||||
|
||||
math.push(parse(function_to_test));
|
||||
}
|
||||
|
||||
// Generate a bunch of random inputs for each function. This will
|
||||
// attempt to generate a good set of uniform test cases for exercising
|
||||
// all the various functionality.
|
||||
generate_random_tests(&mut math, &mut rand::thread_rng());
|
||||
|
||||
// After we have all our inputs, use the x86_64-unknown-linux-musl
|
||||
// target to generate the expected output.
|
||||
generate_test_outputs(&mut math);
|
||||
|
||||
// ... and now that we have both inputs and expected outputs, do a bunch
|
||||
// of codegen to create the unit tests which we'll actually execute.
|
||||
generate_unit_tests(&math);
|
||||
}
|
||||
|
||||
/// A "poor man's" parser for the signature of a function
|
||||
fn parse(s: &str) -> Function {
|
||||
let s = eat(s, "pub fn ");
|
||||
let pos = s.find('(').unwrap();
|
||||
let name = &s[..pos];
|
||||
let s = &s[pos + 1..];
|
||||
let end = s.find(')').unwrap();
|
||||
let args = s[..end]
|
||||
.split(',')
|
||||
.map(|arg| {
|
||||
let colon = arg.find(':').unwrap();
|
||||
parse_ty(arg[colon + 1..].trim())
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let tail = &s[end + 1..];
|
||||
let tail = eat(tail, " -> ");
|
||||
let ret = parse_ty(tail.trim().split(' ').next().unwrap());
|
||||
|
||||
return Function {
|
||||
name: name.to_string(),
|
||||
args,
|
||||
ret,
|
||||
tests: Vec::new(),
|
||||
};
|
||||
|
||||
fn parse_ty(s: &str) -> Ty {
|
||||
match s {
|
||||
"f32" => Ty::F32,
|
||||
"f64" => Ty::F64,
|
||||
"i32" => Ty::I32,
|
||||
"bool" => Ty::Bool,
|
||||
other => panic!("unknown type `{}`", other),
|
||||
}
|
||||
}
|
||||
|
||||
fn eat<'a>(s: &'a str, prefix: &str) -> &'a str {
|
||||
if s.starts_with(prefix) {
|
||||
&s[prefix.len()..]
|
||||
} else {
|
||||
panic!("{:?} didn't start with {:?}", s, prefix)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_random_tests<R: Rng>(functions: &mut [Function], rng: &mut R) {
|
||||
for function in functions {
|
||||
for _ in 0..NTESTS {
|
||||
function.tests.push(generate_test(&function.args, rng));
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_test<R: Rng>(args: &[Ty], rng: &mut R) -> Test {
|
||||
let inputs = args.iter().map(|ty| ty.gen_i64(rng)).collect();
|
||||
// zero output for now since we'll generate it later
|
||||
Test { inputs, output: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Ty {
|
||||
fn gen_i64<R: Rng>(&self, r: &mut R) -> i64 {
|
||||
match self {
|
||||
Ty::F32 => r.gen::<f32>().to_bits().into(),
|
||||
Ty::F64 => r.gen::<f64>().to_bits() as i64,
|
||||
Ty::I32 => {
|
||||
if r.gen_range(0, 10) < 1 {
|
||||
let i = *[i32::max_value(), 0, i32::min_value()].choose(r).unwrap();
|
||||
i.into()
|
||||
} else {
|
||||
r.gen::<i32>().into()
|
||||
}
|
||||
}
|
||||
Ty::Bool => r.gen::<bool>() as i64,
|
||||
}
|
||||
}
|
||||
|
||||
fn libc_ty(&self) -> &'static str {
|
||||
match self {
|
||||
Ty::F32 => "f32",
|
||||
Ty::F64 => "f64",
|
||||
Ty::I32 => "i32",
|
||||
Ty::Bool => "i32",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_test_outputs(functions: &mut [Function]) {
|
||||
let mut src = String::new();
|
||||
let dst = std::env::var("OUT_DIR").unwrap();
|
||||
|
||||
// Generate a program which will run all tests with all inputs in
|
||||
// `functions`. This program will write all outputs to stdout (in a
|
||||
// binary format).
|
||||
src.push_str("use std::io::Write;");
|
||||
src.push_str("fn main() {");
|
||||
src.push_str("let mut result = Vec::new();");
|
||||
for function in functions.iter_mut() {
|
||||
src.push_str("unsafe {");
|
||||
src.push_str("extern { fn ");
|
||||
src.push_str(&function.name);
|
||||
src.push_str("(");
|
||||
for (i, arg) in function.args.iter().enumerate() {
|
||||
src.push_str(&format!("arg{}: {},", i, arg.libc_ty()));
|
||||
}
|
||||
src.push_str(") -> ");
|
||||
src.push_str(function.ret.libc_ty());
|
||||
src.push_str("; }");
|
||||
|
||||
src.push_str(&format!("static TESTS: &[[i64; {}]]", function.args.len()));
|
||||
src.push_str(" = &[");
|
||||
for test in function.tests.iter() {
|
||||
src.push_str("[");
|
||||
for val in test.inputs.iter() {
|
||||
src.push_str(&val.to_string());
|
||||
src.push_str(",");
|
||||
}
|
||||
src.push_str("],");
|
||||
}
|
||||
src.push_str("];");
|
||||
|
||||
src.push_str("for test in TESTS {");
|
||||
src.push_str("let output = ");
|
||||
src.push_str(&function.name);
|
||||
src.push_str("(");
|
||||
for (i, arg) in function.args.iter().enumerate() {
|
||||
src.push_str(&match arg {
|
||||
Ty::F32 => format!("f32::from_bits(test[{}] as u32)", i),
|
||||
Ty::F64 => format!("f64::from_bits(test[{}] as u64)", i),
|
||||
Ty::I32 => format!("test[{}] as i32", i),
|
||||
Ty::Bool => format!("test[{}] as i32", i),
|
||||
});
|
||||
src.push_str(",");
|
||||
}
|
||||
src.push_str(");");
|
||||
src.push_str("let output = ");
|
||||
src.push_str(match function.ret {
|
||||
Ty::F32 => "output.to_bits() as i64",
|
||||
Ty::F64 => "output.to_bits() as i64",
|
||||
Ty::I32 => "output as i64",
|
||||
Ty::Bool => "output as i64",
|
||||
});
|
||||
src.push_str(";");
|
||||
src.push_str("result.extend_from_slice(&output.to_le_bytes());");
|
||||
|
||||
src.push_str("}");
|
||||
|
||||
src.push_str("}");
|
||||
}
|
||||
|
||||
src.push_str("std::io::stdout().write_all(&result).unwrap();");
|
||||
|
||||
src.push_str("}");
|
||||
|
||||
let path = format!("{}/gen.rs", dst);
|
||||
fs::write(&path, src).unwrap();
|
||||
|
||||
// Make it somewhat pretty if something goes wrong
|
||||
drop(Command::new("rustfmt").arg(&path).status());
|
||||
|
||||
// Compile and execute this tests for the musl target, assuming we're an
|
||||
// x86_64 host effectively.
|
||||
let status = Command::new("rustc")
|
||||
.current_dir(&dst)
|
||||
.arg(&path)
|
||||
.arg("--target=x86_64-unknown-linux-musl")
|
||||
.status()
|
||||
.unwrap();
|
||||
assert!(status.success());
|
||||
let output = Command::new("./gen").current_dir(&dst).output().unwrap();
|
||||
assert!(output.status.success());
|
||||
assert!(output.stderr.is_empty());
|
||||
|
||||
// Map all the output bytes back to an `i64` and then shove it all into
|
||||
// the expected results.
|
||||
let mut results = output.stdout.chunks_exact(8).map(|buf| {
|
||||
let mut exact = [0; 8];
|
||||
exact.copy_from_slice(buf);
|
||||
i64::from_le_bytes(exact)
|
||||
});
|
||||
|
||||
for test in functions.iter_mut().flat_map(|f| f.tests.iter_mut()) {
|
||||
test.output = results.next().unwrap();
|
||||
}
|
||||
assert!(results.next().is_none());
|
||||
}
|
||||
|
||||
/// Codegens a file which has a ton of `#[test]` annotations for all the
|
||||
/// tests that we generated above.
|
||||
fn generate_unit_tests(functions: &[Function]) {
|
||||
let mut src = String::new();
|
||||
let dst = std::env::var("OUT_DIR").unwrap();
|
||||
|
||||
for function in functions {
|
||||
src.push_str("#[test]");
|
||||
src.push_str("fn ");
|
||||
src.push_str(&function.name);
|
||||
src.push_str("_matches_musl() {");
|
||||
src.push_str(&format!(
|
||||
"static TESTS: &[([i64; {}], i64)]",
|
||||
function.args.len()
|
||||
));
|
||||
src.push_str(" = &[");
|
||||
for test in function.tests.iter() {
|
||||
src.push_str("([");
|
||||
for val in test.inputs.iter() {
|
||||
src.push_str(&val.to_string());
|
||||
src.push_str(",");
|
||||
}
|
||||
src.push_str("],");
|
||||
src.push_str(&test.output.to_string());
|
||||
src.push_str("),");
|
||||
}
|
||||
src.push_str("];");
|
||||
|
||||
src.push_str("for (test, expected) in TESTS {");
|
||||
src.push_str("let output = ");
|
||||
src.push_str(&function.name);
|
||||
src.push_str("(");
|
||||
for (i, arg) in function.args.iter().enumerate() {
|
||||
src.push_str(&match arg {
|
||||
Ty::F32 => format!("f32::from_bits(test[{}] as u32)", i),
|
||||
Ty::F64 => format!("f64::from_bits(test[{}] as u64)", i),
|
||||
Ty::I32 => format!("test[{}] as i32", i),
|
||||
Ty::Bool => format!("test[{}] as i32", i),
|
||||
});
|
||||
src.push_str(",");
|
||||
}
|
||||
src.push_str(");");
|
||||
src.push_str(match function.ret {
|
||||
Ty::F32 => "if _eqf(output, f32::from_bits(*expected as u32)).is_ok() { continue }",
|
||||
Ty::F64 => "if _eq(output, f64::from_bits(*expected as u64)).is_ok() { continue }",
|
||||
Ty::I32 => "if output as i64 == expected { continue }",
|
||||
Ty::Bool => unreachable!(),
|
||||
});
|
||||
|
||||
src.push_str(
|
||||
r#"
|
||||
panic!("INPUT: {:?} EXPECTED: {:?} ACTUAL {:?}", test, expected, output);
|
||||
"#,
|
||||
);
|
||||
src.push_str("}");
|
||||
|
||||
src.push_str("}");
|
||||
}
|
||||
|
||||
let path = format!("{}/musl-tests.rs", dst);
|
||||
fs::write(&path, src).unwrap();
|
||||
|
||||
// Try to make it somewhat pretty
|
||||
drop(Command::new("rustfmt").arg(&path).status());
|
||||
}
|
||||
}
|
||||
23
library/compiler-builtins/libm/ci/azure-install-rust.yml
Normal file
23
library/compiler-builtins/libm/ci/azure-install-rust.yml
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
steps:
|
||||
- bash: |
|
||||
set -e
|
||||
toolchain=$TOOLCHAIN
|
||||
if [ "$toolchain" = "" ]; then
|
||||
toolchain=stable
|
||||
fi
|
||||
curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $toolchain
|
||||
echo "##vso[task.prependpath]$HOME/.cargo/bin"
|
||||
displayName: Install rust (unix)
|
||||
condition: ne( variables['Agent.OS'], 'Windows_NT' )
|
||||
|
||||
- script: |
|
||||
curl -sSf -o rustup-init.exe https://win.rustup.rs
|
||||
rustup-init.exe -y --default-toolchain stable-%TARGET%
|
||||
echo ##vso[task.prependpath]%USERPROFILE%\.cargo\bin
|
||||
displayName: Install rust (windows)
|
||||
condition: eq( variables['Agent.OS'], 'Windows_NT' )
|
||||
|
||||
- script: |
|
||||
rustc -Vv
|
||||
cargo -V
|
||||
displayName: Query rust and cargo versions
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
FROM ubuntu:18.04
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
gcc libc6-dev ca-certificates \
|
||||
gcc-aarch64-linux-gnu libc6-dev-arm64-cross \
|
||||
qemu-user-static
|
||||
ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \
|
||||
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-aarch64-static \
|
||||
QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \
|
||||
RUST_TEST_THREADS=1
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
FROM ubuntu:18.04
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
gcc libc6-dev ca-certificates \
|
||||
gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static
|
||||
ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \
|
||||
CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_RUNNER=qemu-arm-static \
|
||||
QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \
|
||||
RUST_TEST_THREADS=1
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
FROM ubuntu:18.04
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
gcc libc6-dev ca-certificates \
|
||||
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static
|
||||
ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \
|
||||
CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \
|
||||
QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \
|
||||
RUST_TEST_THREADS=1
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
FROM ubuntu:18.04
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
gcc libc6-dev ca-certificates \
|
||||
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static
|
||||
ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \
|
||||
CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \
|
||||
QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \
|
||||
RUST_TEST_THREADS=1
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
FROM ubuntu:18.04
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
gcc-multilib libc6-dev ca-certificates
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
FROM ubuntu:18.04
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
gcc libc6-dev ca-certificates \
|
||||
gcc-mips-linux-gnu libc6-dev-mips-cross \
|
||||
binfmt-support qemu-user-static qemu-system-mips
|
||||
|
||||
ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc \
|
||||
CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_RUNNER=qemu-mips-static \
|
||||
QEMU_LD_PREFIX=/usr/mips-linux-gnu \
|
||||
RUST_TEST_THREADS=1
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
FROM ubuntu:18.04
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
gcc \
|
||||
gcc-mips64-linux-gnuabi64 \
|
||||
libc6-dev \
|
||||
libc6-dev-mips64-cross \
|
||||
qemu-user-static \
|
||||
qemu-system-mips
|
||||
ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER=mips64-linux-gnuabi64-gcc \
|
||||
CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64-static \
|
||||
CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \
|
||||
QEMU_LD_PREFIX=/usr/mips64-linux-gnuabi64 \
|
||||
RUST_TEST_THREADS=1
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
FROM ubuntu:18.04
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
gcc \
|
||||
gcc-mips64el-linux-gnuabi64 \
|
||||
libc6-dev \
|
||||
libc6-dev-mips64el-cross \
|
||||
qemu-user-static
|
||||
ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER=mips64el-linux-gnuabi64-gcc \
|
||||
CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64el-static \
|
||||
CC_mips64el_unknown_linux_gnuabi64=mips64el-linux-gnuabi64-gcc \
|
||||
QEMU_LD_PREFIX=/usr/mips64el-linux-gnuabi64 \
|
||||
RUST_TEST_THREADS=1
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
FROM ubuntu:18.04
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
gcc libc6-dev ca-certificates \
|
||||
gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \
|
||||
binfmt-support qemu-user-static
|
||||
|
||||
ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER=mipsel-linux-gnu-gcc \
|
||||
CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_RUNNER=qemu-mipsel-static \
|
||||
QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \
|
||||
RUST_TEST_THREADS=1
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
FROM ubuntu:18.04
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
gcc libc6-dev qemu-user-static ca-certificates \
|
||||
gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \
|
||||
qemu-system-ppc
|
||||
|
||||
ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER=powerpc-linux-gnu-gcc \
|
||||
CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc-static \
|
||||
QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \
|
||||
RUST_TEST_THREADS=1
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
FROM ubuntu:18.04
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
gcc libc6-dev ca-certificates \
|
||||
gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \
|
||||
binfmt-support qemu-user-static qemu-system-ppc
|
||||
|
||||
ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \
|
||||
CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64-static \
|
||||
CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc \
|
||||
QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu \
|
||||
RUST_TEST_THREADS=1
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
FROM ubuntu:18.04
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
gcc libc6-dev qemu-user-static ca-certificates \
|
||||
gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \
|
||||
qemu-system-ppc
|
||||
|
||||
ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \
|
||||
CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64le-static \
|
||||
QEMU_CPU=POWER8 \
|
||||
QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \
|
||||
RUST_TEST_THREADS=1
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
FROM ubuntu:18.04
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
gcc libc6-dev ca-certificates
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
set -euxo pipefail
|
||||
|
||||
main() {
|
||||
if [ $TARGET = cargo-fmt ]; then
|
||||
rustup component add rustfmt-preview
|
||||
return
|
||||
fi
|
||||
|
||||
if ! hash cross >/dev/null 2>&1; then
|
||||
cargo install cross
|
||||
fi
|
||||
|
||||
rustup target add x86_64-unknown-linux-musl
|
||||
|
||||
if [ $TARGET != x86_64-unknown-linux-gnu ]; then
|
||||
rustup target add $TARGET
|
||||
fi
|
||||
|
||||
mkdir -p ~/.local/bin
|
||||
curl -L https://github.com/japaric/qemu-bin/raw/master/14.04/qemu-arm-2.12.0 > ~/.local/bin/qemu-arm
|
||||
chmod +x ~/.local/bin/qemu-arm
|
||||
qemu-arm --version
|
||||
}
|
||||
|
||||
main
|
||||
37
library/compiler-builtins/libm/ci/run-docker.sh
Executable file
37
library/compiler-builtins/libm/ci/run-docker.sh
Executable file
|
|
@ -0,0 +1,37 @@
|
|||
# Small script to run tests for a target (or all targets) inside all the
|
||||
# respective docker images.
|
||||
|
||||
set -ex
|
||||
|
||||
run() {
|
||||
local target=$1
|
||||
|
||||
echo $target
|
||||
|
||||
# This directory needs to exist before calling docker, otherwise docker will create it but it
|
||||
# will be owned by root
|
||||
mkdir -p target
|
||||
|
||||
docker build -t $target ci/docker/$target
|
||||
docker run \
|
||||
--rm \
|
||||
--user $(id -u):$(id -g) \
|
||||
-e CARGO_HOME=/cargo \
|
||||
-e CARGO_TARGET_DIR=/target \
|
||||
-v $HOME/.cargo:/cargo \
|
||||
-v `pwd`/target:/target \
|
||||
-v `pwd`:/checkout:ro \
|
||||
-v `rustc --print sysroot`:/rust:ro \
|
||||
--init \
|
||||
-w /checkout \
|
||||
$target \
|
||||
sh -c "HOME=/tmp PATH=\$PATH:/rust/bin exec ci/run.sh $target"
|
||||
}
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
for d in `ls ci/docker/`; do
|
||||
run $d
|
||||
done
|
||||
else
|
||||
run $1
|
||||
fi
|
||||
12
library/compiler-builtins/libm/ci/run.sh
Executable file
12
library/compiler-builtins/libm/ci/run.sh
Executable file
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -ex
|
||||
TARGET=$1
|
||||
|
||||
cargo test --target $TARGET
|
||||
cargo test --target $TARGET --release
|
||||
|
||||
# FIXME(#4) overflow checks in non-release currently cause issues
|
||||
#cargo test --features 'checked musl-reference-tests' --target $TARGET
|
||||
|
||||
cargo test --features 'checked musl-reference-tests' --target $TARGET --release
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
set -euxo pipefail
|
||||
|
||||
main() {
|
||||
if [ $TARGET = cargo-fmt ]; then
|
||||
cargo fmt -- --check
|
||||
return
|
||||
fi
|
||||
|
||||
# quick check
|
||||
cargo check
|
||||
|
||||
# check that we can source import libm into compiler-builtins
|
||||
cargo check --package cb
|
||||
|
||||
# generate tests
|
||||
cargo run -p input-generator --target x86_64-unknown-linux-musl
|
||||
cargo run -p musl-generator --target x86_64-unknown-linux-musl
|
||||
cargo run -p newlib-generator
|
||||
|
||||
# test that the functions don't contain invocations of `panic!`
|
||||
case $TARGET in
|
||||
armv7-unknown-linux-gnueabihf)
|
||||
cross build --release --target $TARGET --example no-panic
|
||||
;;
|
||||
esac
|
||||
|
||||
# run unit tests
|
||||
cross test --lib --features checked --target $TARGET --release
|
||||
|
||||
# run generated tests
|
||||
cross test --tests --features checked --target $TARGET --release
|
||||
|
||||
# TODO need to fix overflow issues (cf. issue #4)
|
||||
# cross test --target $TARGET
|
||||
}
|
||||
|
||||
main
|
||||
|
|
@ -5,5 +5,5 @@
|
|||
#![allow(dead_code)]
|
||||
#![no_std]
|
||||
|
||||
#[path = "../../src/math/mod.rs"]
|
||||
#[path = "../../../src/math/mod.rs"]
|
||||
mod libm;
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
#![feature(lang_items)]
|
||||
#![feature(panic_implementation)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
extern crate libm;
|
||||
|
||||
use core::panic::PanicInfo;
|
||||
use core::ptr;
|
||||
|
||||
macro_rules! force_eval {
|
||||
($e:expr) => {
|
||||
unsafe {
|
||||
core::ptr::read_volatile(&$e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main() {
|
||||
force_eval!(libm::acos(random()));
|
||||
force_eval!(libm::acosf(random()));
|
||||
force_eval!(libm::asin(random()));
|
||||
force_eval!(libm::asinf(random()));
|
||||
force_eval!(libm::atan(random()));
|
||||
force_eval!(libm::atan2(random(), random()));
|
||||
force_eval!(libm::atan2f(random(), random()));
|
||||
force_eval!(libm::atanf(random()));
|
||||
force_eval!(libm::cbrt(random()));
|
||||
force_eval!(libm::cbrtf(random()));
|
||||
force_eval!(libm::ceil(random()));
|
||||
force_eval!(libm::ceilf(random()));
|
||||
force_eval!(libm::cos(random()));
|
||||
force_eval!(libm::cosf(random()));
|
||||
force_eval!(libm::cosh(random()));
|
||||
force_eval!(libm::coshf(random()));
|
||||
force_eval!(libm::exp(random()));
|
||||
force_eval!(libm::exp2(random()));
|
||||
force_eval!(libm::exp2f(random()));
|
||||
force_eval!(libm::expf(random()));
|
||||
force_eval!(libm::expm1(random()));
|
||||
force_eval!(libm::expm1f(random()));
|
||||
force_eval!(libm::fabs(random()));
|
||||
force_eval!(libm::fabsf(random()));
|
||||
force_eval!(libm::fdim(random(), random()));
|
||||
force_eval!(libm::fdimf(random(), random()));
|
||||
force_eval!(libm::floor(random()));
|
||||
force_eval!(libm::floorf(random()));
|
||||
force_eval!(libm::fma(random(), random(), random()));
|
||||
force_eval!(libm::fmaf(random(), random(), random()));
|
||||
force_eval!(libm::fmod(random(), random()));
|
||||
force_eval!(libm::fmodf(random(), random()));
|
||||
force_eval!(libm::hypot(random(), random()));
|
||||
force_eval!(libm::hypotf(random(), random()));
|
||||
force_eval!(libm::log(random()));
|
||||
force_eval!(libm::log2(random()));
|
||||
force_eval!(libm::log10(random()));
|
||||
force_eval!(libm::log10f(random()));
|
||||
force_eval!(libm::log1p(random()));
|
||||
force_eval!(libm::log1pf(random()));
|
||||
force_eval!(libm::log2f(random()));
|
||||
force_eval!(libm::logf(random()));
|
||||
force_eval!(libm::pow(random(), random()));
|
||||
force_eval!(libm::powf(random(), random()));
|
||||
force_eval!(libm::round(random()));
|
||||
force_eval!(libm::roundf(random()));
|
||||
force_eval!(libm::scalbn(random(), random()));
|
||||
force_eval!(libm::scalbnf(random(), random()));
|
||||
force_eval!(libm::sin(random()));
|
||||
force_eval!(libm::sinf(random()));
|
||||
force_eval!(libm::sinh(random()));
|
||||
force_eval!(libm::sinhf(random()));
|
||||
force_eval!(libm::sqrt(random()));
|
||||
force_eval!(libm::sqrtf(random()));
|
||||
force_eval!(libm::tan(random()));
|
||||
force_eval!(libm::tanf(random()));
|
||||
force_eval!(libm::tanh(random()));
|
||||
force_eval!(libm::tanhf(random()));
|
||||
force_eval!(libm::trunc(random()));
|
||||
force_eval!(libm::truncf(random()));
|
||||
}
|
||||
|
||||
fn random<T>() -> T
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
unsafe {
|
||||
static mut X: usize = 0;
|
||||
X += 8;
|
||||
ptr::read_volatile(X as *const T)
|
||||
}
|
||||
}
|
||||
|
||||
#[panic_implementation]
|
||||
#[no_mangle]
|
||||
pub fn panic(_info: &PanicInfo) -> ! {
|
||||
// loop {}
|
||||
extern "C" {
|
||||
fn thou_shalt_not_panic() -> !;
|
||||
}
|
||||
|
||||
unsafe { thou_shalt_not_panic() }
|
||||
}
|
||||
|
||||
#[link(name = "c")]
|
||||
extern "C" {}
|
||||
|
||||
#[lang = "eh_personality"]
|
||||
fn eh() {}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __aeabi_unwind_cpp_pr0() {}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __aeabi_unwind_cpp_pr1() {}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
[package]
|
||||
name = "input-generator"
|
||||
version = "0.1.0"
|
||||
authors = ["Jorge Aparicio <jorge@japaric.io>"]
|
||||
|
||||
[dependencies]
|
||||
rand = "0.5.4"
|
||||
|
|
@ -1,189 +0,0 @@
|
|||
extern crate rand;
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::error::Error;
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
|
||||
use rand::{RngCore, SeedableRng, XorShiftRng};
|
||||
|
||||
const NTESTS: usize = 10_000;
|
||||
|
||||
fn main() -> Result<(), Box<Error>> {
|
||||
let mut rng = XorShiftRng::from_rng(&mut rand::thread_rng())?;
|
||||
|
||||
fs::remove_dir_all("bin").ok();
|
||||
fs::create_dir_all("bin/input")?;
|
||||
fs::create_dir_all("bin/output")?;
|
||||
|
||||
f32(&mut rng)?;
|
||||
f32f32(&mut rng)?;
|
||||
f32f32f32(&mut rng)?;
|
||||
f32i16(&mut rng)?;
|
||||
f64(&mut rng)?;
|
||||
f64f64(&mut rng)?;
|
||||
f64f64f64(&mut rng)?;
|
||||
f64i16(&mut rng)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn f32(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
|
||||
let mut set = BTreeSet::new();
|
||||
|
||||
while set.len() < NTESTS {
|
||||
let f = f32::from_bits(rng.next_u32());
|
||||
|
||||
if f.is_nan() {
|
||||
continue;
|
||||
}
|
||||
|
||||
set.insert(f.to_bits());
|
||||
}
|
||||
|
||||
let mut f = File::create("bin/input/f32")?;
|
||||
for i in set {
|
||||
f.write_all(&i.to_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn f32f32(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
|
||||
let mut f = File::create("bin/input/f32f32")?;
|
||||
let mut i = 0;
|
||||
while i < NTESTS {
|
||||
let x0 = f32::from_bits(rng.next_u32());
|
||||
let x1 = f32::from_bits(rng.next_u32());
|
||||
|
||||
if x0.is_nan() || x1.is_nan() {
|
||||
continue;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
f.write_all(&x0.to_bits().to_bytes())?;
|
||||
f.write_all(&x1.to_bits().to_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn f32i16(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
|
||||
let mut f = File::create("bin/input/f32i16")?;
|
||||
let mut i = 0;
|
||||
while i < NTESTS {
|
||||
let x0 = f32::from_bits(rng.next_u32());
|
||||
let x1 = rng.next_u32() as i16;
|
||||
|
||||
if x0.is_nan() {
|
||||
continue;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
f.write_all(&x0.to_bits().to_bytes())?;
|
||||
f.write_all(&x1.to_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn f32f32f32(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
|
||||
let mut f = File::create("bin/input/f32f32f32")?;
|
||||
let mut i = 0;
|
||||
while i < NTESTS {
|
||||
let x0 = f32::from_bits(rng.next_u32());
|
||||
let x1 = f32::from_bits(rng.next_u32());
|
||||
let x2 = f32::from_bits(rng.next_u32());
|
||||
|
||||
if x0.is_nan() || x1.is_nan() || x2.is_nan() {
|
||||
continue;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
f.write_all(&x0.to_bits().to_bytes())?;
|
||||
f.write_all(&x1.to_bits().to_bytes())?;
|
||||
f.write_all(&x2.to_bits().to_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn f64(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
|
||||
let mut set = BTreeSet::new();
|
||||
|
||||
while set.len() < NTESTS {
|
||||
let f = f64::from_bits(rng.next_u64());
|
||||
|
||||
if f.is_nan() {
|
||||
continue;
|
||||
}
|
||||
|
||||
set.insert(f.to_bits());
|
||||
}
|
||||
|
||||
let mut f = File::create("bin/input/f64")?;
|
||||
for i in set {
|
||||
f.write_all(&i.to_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn f64f64(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
|
||||
let mut f = File::create("bin/input/f64f64")?;
|
||||
let mut i = 0;
|
||||
while i < NTESTS {
|
||||
let x0 = f64::from_bits(rng.next_u64());
|
||||
let x1 = f64::from_bits(rng.next_u64());
|
||||
|
||||
if x0.is_nan() || x1.is_nan() {
|
||||
continue;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
f.write_all(&x0.to_bits().to_bytes())?;
|
||||
f.write_all(&x1.to_bits().to_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn f64f64f64(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
|
||||
let mut f = File::create("bin/input/f64f64f64")?;
|
||||
let mut i = 0;
|
||||
while i < NTESTS {
|
||||
let x0 = f64::from_bits(rng.next_u64());
|
||||
let x1 = f64::from_bits(rng.next_u64());
|
||||
let x2 = f64::from_bits(rng.next_u64());
|
||||
|
||||
if x0.is_nan() || x1.is_nan() || x2.is_nan() {
|
||||
continue;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
f.write_all(&x0.to_bits().to_bytes())?;
|
||||
f.write_all(&x1.to_bits().to_bytes())?;
|
||||
f.write_all(&x2.to_bits().to_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn f64i16(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
|
||||
let mut f = File::create("bin/input/f64i16")?;
|
||||
let mut i = 0;
|
||||
while i < NTESTS {
|
||||
let x0 = f64::from_bits(rng.next_u64());
|
||||
let x1 = rng.next_u32() as i16;
|
||||
|
||||
if x0.is_nan() {
|
||||
continue;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
f.write_all(&x0.to_bits().to_bytes())?;
|
||||
f.write_all(&x1.to_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
[target.thumbv7em-none-eabi]
|
||||
rustflags = [
|
||||
"-C", "link-arg=-Wl,-Tlink.x",
|
||||
"-C", "link-arg=-nostartfiles",
|
||||
"-C", "link-arg=-mthumb",
|
||||
"-C", "link-arg=-march=armv7e-m",
|
||||
"-C", "link-arg=-mfloat-abi=soft",
|
||||
]
|
||||
|
||||
[build]
|
||||
target = "thumbv7em-none-eabi"
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "math"
|
||||
version = "0.0.0"
|
||||
|
||||
[dependencies]
|
||||
qemu-arm-rt = { git = "https://github.com/japaric/qemu-arm-rt" }
|
||||
|
||||
[workspace]
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
[target.thumbv7em-none-eabi]
|
||||
xargo = false
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
[package]
|
||||
name = "musl-generator"
|
||||
version = "0.1.0"
|
||||
authors = ["Jorge Aparicio <jorge@japaric.io>"]
|
||||
|
||||
[dependencies]
|
||||
lazy_static = "1.0.2"
|
||||
shared = { path = "../shared" }
|
||||
libm = { path = ".." }
|
||||
|
|
@ -1,191 +0,0 @@
|
|||
macro_rules! f32 {
|
||||
($($fun:ident,)+) => {{
|
||||
$(
|
||||
// check type signature
|
||||
let _: fn(f32) -> f32 = libm::$fun;
|
||||
let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?;
|
||||
)+
|
||||
|
||||
for x in shared::F32.iter() {
|
||||
$(
|
||||
let y = unsafe {
|
||||
extern "C" {
|
||||
fn $fun(_: f32) -> f32;
|
||||
}
|
||||
|
||||
$fun(*x)
|
||||
};
|
||||
|
||||
$fun.write_all(&y.to_bits().to_bytes())?;
|
||||
)+
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! f32f32 {
|
||||
($($fun:ident,)+) => {{
|
||||
$(
|
||||
// check type signature
|
||||
let _: fn(f32, f32) -> f32 = libm::$fun;
|
||||
let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?;
|
||||
)+
|
||||
|
||||
for (x0, x1) in shared::F32F32.iter() {
|
||||
$(
|
||||
let y = unsafe {
|
||||
extern "C" {
|
||||
fn $fun(_: f32, _: f32) -> f32;
|
||||
}
|
||||
|
||||
$fun(*x0, *x1)
|
||||
};
|
||||
|
||||
$fun.write_all(&y.to_bits().to_bytes())?;
|
||||
)+
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! f32f32f32 {
|
||||
($($fun:ident,)+) => {{
|
||||
$(
|
||||
// check type signature
|
||||
let _: fn(f32, f32, f32) -> f32 = libm::$fun;
|
||||
let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?;
|
||||
)+
|
||||
|
||||
for (x0, x1, x2) in shared::F32F32F32.iter() {
|
||||
$(
|
||||
let y = unsafe {
|
||||
extern "C" {
|
||||
fn $fun(_: f32, _: f32, _: f32) -> f32;
|
||||
}
|
||||
|
||||
$fun(*x0, *x1, *x2)
|
||||
};
|
||||
|
||||
$fun.write_all(&y.to_bits().to_bytes())?;
|
||||
)+
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! f32i32 {
|
||||
($($fun:ident,)+) => {{
|
||||
$(
|
||||
// check type signature
|
||||
let _: fn(f32, i32) -> f32 = libm::$fun;
|
||||
let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?;
|
||||
)+
|
||||
|
||||
for (x0, x1) in shared::F32I32.iter() {
|
||||
$(
|
||||
let y = unsafe {
|
||||
extern "C" {
|
||||
fn $fun(_: f32, _: i32) -> f32;
|
||||
}
|
||||
|
||||
$fun(*x0, *x1 as i32)
|
||||
};
|
||||
|
||||
$fun.write_all(&y.to_bits().to_bytes())?;
|
||||
)+
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! f64 {
|
||||
($($fun:ident,)+) => {{
|
||||
$(
|
||||
// check type signature
|
||||
let _: fn(f64) -> f64 = libm::$fun;
|
||||
let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?;
|
||||
)+
|
||||
|
||||
for x in shared::F64.iter() {
|
||||
$(
|
||||
let y = unsafe {
|
||||
extern "C" {
|
||||
fn $fun(_: f64) -> f64;
|
||||
}
|
||||
|
||||
$fun(*x)
|
||||
};
|
||||
|
||||
$fun.write_all(&y.to_bits().to_bytes())?;
|
||||
)+
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! f64f64 {
|
||||
($($fun:ident,)+) => {{
|
||||
$(
|
||||
// check type signature
|
||||
let _: fn(f64, f64) -> f64 = libm::$fun;
|
||||
let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?;
|
||||
)+
|
||||
|
||||
for (x0, x1) in shared::F64F64.iter() {
|
||||
$(
|
||||
let y = unsafe {
|
||||
extern "C" {
|
||||
fn $fun(_: f64, _: f64) -> f64;
|
||||
}
|
||||
|
||||
$fun(*x0, *x1)
|
||||
};
|
||||
|
||||
$fun.write_all(&y.to_bits().to_bytes())?;
|
||||
)+
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! f64f64f64 {
|
||||
($($fun:ident,)+) => {{
|
||||
$(
|
||||
// check type signature
|
||||
let _: fn(f64, f64, f64) -> f64 = libm::$fun;
|
||||
let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?;
|
||||
)+
|
||||
|
||||
for (x0, x1, x2) in shared::F64F64F64.iter() {
|
||||
$(
|
||||
let y = unsafe {
|
||||
extern "C" {
|
||||
fn $fun(_: f64, _: f64, _: f64) -> f64;
|
||||
}
|
||||
|
||||
$fun(*x0, *x1, *x2)
|
||||
};
|
||||
|
||||
$fun.write_all(&y.to_bits().to_bytes())?;
|
||||
)+
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! f64i32 {
|
||||
($($fun:ident,)+) => {{
|
||||
$(
|
||||
// check type signature
|
||||
let _: fn(f64, i32) -> f64 = libm::$fun;
|
||||
let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?;
|
||||
)+
|
||||
|
||||
for (x0, x1) in shared::F64I32.iter() {
|
||||
$(
|
||||
let y = unsafe {
|
||||
extern "C" {
|
||||
fn $fun(_: f64, _: i32) -> f64;
|
||||
}
|
||||
|
||||
$fun(*x0, *x1 as i32)
|
||||
};
|
||||
|
||||
$fun.write_all(&y.to_bits().to_bytes())?;
|
||||
)+
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
extern crate libm;
|
||||
extern crate shared;
|
||||
|
||||
use std::error::Error;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
fn main() -> Result<(), Box<Error>> {
|
||||
f32! {
|
||||
acosf,
|
||||
asinf,
|
||||
atanf,
|
||||
cbrtf,
|
||||
ceilf,
|
||||
cosf,
|
||||
coshf,
|
||||
exp2f,
|
||||
expf,
|
||||
expm1f,
|
||||
fabsf,
|
||||
floorf,
|
||||
log10f,
|
||||
log1pf,
|
||||
log2f,
|
||||
logf,
|
||||
roundf,
|
||||
sinf,
|
||||
sinhf,
|
||||
sqrtf,
|
||||
tanf,
|
||||
tanhf,
|
||||
truncf,
|
||||
}
|
||||
|
||||
f32f32! {
|
||||
atan2f,
|
||||
fdimf,
|
||||
fmodf,
|
||||
hypotf,
|
||||
powf,
|
||||
}
|
||||
|
||||
f32i32! {
|
||||
scalbnf,
|
||||
}
|
||||
|
||||
f32f32f32! {
|
||||
fmaf,
|
||||
}
|
||||
|
||||
f64! {
|
||||
acos,
|
||||
asin,
|
||||
atan,
|
||||
cbrt,
|
||||
ceil,
|
||||
cos,
|
||||
cosh,
|
||||
exp,
|
||||
exp2,
|
||||
expm1,
|
||||
fabs,
|
||||
floor,
|
||||
log,
|
||||
log10,
|
||||
log1p,
|
||||
log2,
|
||||
round,
|
||||
sin,
|
||||
sinh,
|
||||
sqrt,
|
||||
tan,
|
||||
tanh,
|
||||
trunc,
|
||||
}
|
||||
|
||||
f64f64! {
|
||||
atan2,
|
||||
fdim,
|
||||
fmod,
|
||||
hypot,
|
||||
pow,
|
||||
}
|
||||
|
||||
f64i32! {
|
||||
scalbn,
|
||||
}
|
||||
|
||||
f64f64f64! {
|
||||
fma,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
[package]
|
||||
name = "newlib-generator"
|
||||
version = "0.1.0"
|
||||
authors = ["Jorge Aparicio <jorge@japaric.io>"]
|
||||
|
||||
[dependencies]
|
||||
shared = { path = "../shared" }
|
||||
|
|
@ -1,245 +0,0 @@
|
|||
macro_rules! f32 {
|
||||
($($fun:ident,)+) => {
|
||||
$(
|
||||
let fun = stringify!($fun);
|
||||
|
||||
fs::create_dir_all("math/src")?;
|
||||
|
||||
let main = format!("
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
#[macro_use]
|
||||
extern crate qemu_arm_rt as rt;
|
||||
|
||||
use core::u32;
|
||||
|
||||
use rt::{{io, process}};
|
||||
|
||||
entry!(main);
|
||||
|
||||
fn main() {{
|
||||
run().unwrap_or_else(|e| {{
|
||||
eprintln!(\"error: {{}}\", e);
|
||||
process::exit(1);
|
||||
}})
|
||||
}}
|
||||
|
||||
fn run() -> Result<(), usize> {{
|
||||
#[link(name = \"m\")]
|
||||
extern \"C\" {{
|
||||
fn {0}(_: f32) -> f32;
|
||||
}}
|
||||
|
||||
let mut buf = [0; 4];
|
||||
while let Ok(()) = io::Stdin.read_exact(&mut buf) {{
|
||||
let x = f32::from_bits(u32::from_bytes(buf));
|
||||
let y = unsafe {{ {0}(x) }};
|
||||
|
||||
io::Stdout.write_all(&y.to_bits().to_bytes())?;
|
||||
}}
|
||||
|
||||
Ok(())
|
||||
}}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn __errno() -> *mut i32 {{
|
||||
static mut ERRNO: i32 = 0;
|
||||
unsafe {{ &mut ERRNO }}
|
||||
}}
|
||||
", fun);
|
||||
|
||||
File::create("math/src/main.rs")?.write_all(main.as_bytes())?;
|
||||
|
||||
assert!(
|
||||
Command::new("cross")
|
||||
.args(&["build", "--target", "thumbv7em-none-eabi", "--release"])
|
||||
.current_dir("math")
|
||||
.status()?
|
||||
.success()
|
||||
);
|
||||
|
||||
let mut qemu = Command::new("qemu-arm")
|
||||
.arg("math/target/thumbv7em-none-eabi/release/math")
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()?;
|
||||
|
||||
qemu.stdin.as_mut().take().unwrap().write_all(F32)?;
|
||||
|
||||
let output = qemu.wait_with_output()?;
|
||||
|
||||
File::create(concat!("bin/output/newlib.", stringify!($fun)))?
|
||||
.write_all(&output.stdout)?;
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! f32f32 {
|
||||
($($fun:ident,)+) => {
|
||||
$(
|
||||
let fun = stringify!($fun);
|
||||
|
||||
fs::create_dir_all("math/src")?;
|
||||
|
||||
let main = format!("
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
#[macro_use]
|
||||
extern crate qemu_arm_rt as rt;
|
||||
|
||||
use core::u32;
|
||||
|
||||
use rt::{{io, process}};
|
||||
|
||||
entry!(main);
|
||||
|
||||
fn main() {{
|
||||
run().unwrap_or_else(|e| {{
|
||||
eprintln!(\"error: {{}}\", e);
|
||||
process::exit(1);
|
||||
}})
|
||||
}}
|
||||
|
||||
fn run() -> Result<(), usize> {{
|
||||
#[link(name = \"m\")]
|
||||
extern \"C\" {{
|
||||
fn {0}(_: f32, _: f32) -> f32;
|
||||
}}
|
||||
|
||||
let mut chunk = [0; 8];
|
||||
while let Ok(()) = io::Stdin.read_exact(&mut chunk) {{
|
||||
let mut buf = [0; 4];
|
||||
buf.copy_from_slice(&chunk[..4]);
|
||||
let x0 = f32::from_bits(u32::from_bytes(buf));
|
||||
|
||||
buf.copy_from_slice(&chunk[4..]);
|
||||
let x1 = f32::from_bits(u32::from_bytes(buf));
|
||||
|
||||
let y = unsafe {{ {0}(x0, x1) }};
|
||||
|
||||
io::Stdout.write_all(&y.to_bits().to_bytes())?;
|
||||
}}
|
||||
|
||||
Ok(())
|
||||
}}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn __errno() -> *mut i32 {{
|
||||
static mut ERRNO: i32 = 0;
|
||||
unsafe {{ &mut ERRNO }}
|
||||
}}
|
||||
", fun);
|
||||
|
||||
File::create("math/src/main.rs")?.write_all(main.as_bytes())?;
|
||||
|
||||
assert!(
|
||||
Command::new("cross")
|
||||
.args(&["build", "--target", "thumbv7em-none-eabi", "--release"])
|
||||
.current_dir("math")
|
||||
.status()?
|
||||
.success()
|
||||
);
|
||||
|
||||
let mut qemu = Command::new("qemu-arm")
|
||||
.arg("math/target/thumbv7em-none-eabi/release/math")
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()?;
|
||||
|
||||
qemu.stdin.as_mut().take().unwrap().write_all(F32)?;
|
||||
|
||||
let output = qemu.wait_with_output()?;
|
||||
|
||||
File::create(concat!("bin/output/newlib.", stringify!($fun)))?
|
||||
.write_all(&output.stdout)?;
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! f32f32f32 {
|
||||
($($fun:ident,)+) => {
|
||||
$(
|
||||
let fun = stringify!($fun);
|
||||
|
||||
fs::create_dir_all("math/src")?;
|
||||
|
||||
let main = format!("
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
#[macro_use]
|
||||
extern crate qemu_arm_rt as rt;
|
||||
|
||||
use core::u32;
|
||||
|
||||
use rt::{{io, process}};
|
||||
|
||||
entry!(main);
|
||||
|
||||
fn main() {{
|
||||
run().unwrap_or_else(|e| {{
|
||||
eprintln!(\"error: {{}}\", e);
|
||||
process::exit(1);
|
||||
}})
|
||||
}}
|
||||
|
||||
fn run() -> Result<(), usize> {{
|
||||
#[link(name = \"m\")]
|
||||
extern \"C\" {{
|
||||
fn {0}(_: f32, _: f32, _: f32) -> f32;
|
||||
}}
|
||||
|
||||
let mut chunk = [0; 12];
|
||||
while let Ok(()) = io::Stdin.read_exact(&mut chunk) {{
|
||||
let mut buf = [0; 4];
|
||||
buf.copy_from_slice(&chunk[..4]);
|
||||
let x0 = f32::from_bits(u32::from_bytes(buf));
|
||||
|
||||
buf.copy_from_slice(&chunk[4..8]);
|
||||
let x1 = f32::from_bits(u32::from_bytes(buf));
|
||||
|
||||
buf.copy_from_slice(&chunk[8..]);
|
||||
let x2 = f32::from_bits(u32::from_bytes(buf));
|
||||
|
||||
let y = unsafe {{ {0}(x0, x1, x2) }};
|
||||
|
||||
io::Stdout.write_all(&y.to_bits().to_bytes())?;
|
||||
}}
|
||||
|
||||
Ok(())
|
||||
}}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn __errno() -> *mut i32 {{
|
||||
static mut ERRNO: i32 = 0;
|
||||
unsafe {{ &mut ERRNO }}
|
||||
}}
|
||||
", fun);
|
||||
|
||||
File::create("math/src/main.rs")?.write_all(main.as_bytes())?;
|
||||
|
||||
assert!(
|
||||
Command::new("cross")
|
||||
.args(&["build", "--target", "thumbv7em-none-eabi", "--release"])
|
||||
.current_dir("math")
|
||||
.status()?
|
||||
.success()
|
||||
);
|
||||
|
||||
let mut qemu = Command::new("qemu-arm")
|
||||
.arg("math/target/thumbv7em-none-eabi/release/math")
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()?;
|
||||
|
||||
qemu.stdin.as_mut().take().unwrap().write_all(F32)?;
|
||||
|
||||
let output = qemu.wait_with_output()?;
|
||||
|
||||
File::create(concat!("bin/output/newlib.", stringify!($fun)))?
|
||||
.write_all(&output.stdout)?;
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
extern crate shared;
|
||||
|
||||
use std::error::Error;
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
fn main() -> Result<(), Box<Error>> {
|
||||
const F32: &[u8] = include_bytes!("../../bin/input/f32");
|
||||
|
||||
f32! {
|
||||
asinf,
|
||||
cbrtf,
|
||||
cosf,
|
||||
exp2f,
|
||||
sinf,
|
||||
tanf,
|
||||
}
|
||||
|
||||
f32f32! {
|
||||
hypotf,
|
||||
}
|
||||
|
||||
f32f32f32! {
|
||||
fmaf,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
[package]
|
||||
name = "shared"
|
||||
version = "0.1.0"
|
||||
authors = ["Jorge Aparicio <jorge@japaric.io>"]
|
||||
|
||||
[dependencies]
|
||||
lazy_static = "1.0.2"
|
||||
|
|
@ -1,471 +0,0 @@
|
|||
#![feature(exact_chunks)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref F32: Vec<f32> = {
|
||||
let bytes = include_bytes!("../../bin/input/f32");
|
||||
|
||||
bytes
|
||||
.exact_chunks(4)
|
||||
.map(|chunk| {
|
||||
let mut buf = [0; 4];
|
||||
buf.copy_from_slice(chunk);
|
||||
f32::from_bits(u32::from_le(u32::from_bytes(buf)))
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
pub static ref F32F32: Vec<(f32, f32)> = {
|
||||
let bytes = include_bytes!("../../bin/input/f32f32");
|
||||
|
||||
bytes
|
||||
.exact_chunks(8)
|
||||
.map(|chunk| {
|
||||
let mut x0 = [0; 4];
|
||||
let mut x1 = [0; 4];
|
||||
x0.copy_from_slice(&chunk[..4]);
|
||||
x1.copy_from_slice(&chunk[4..]);
|
||||
|
||||
(
|
||||
f32::from_bits(u32::from_le(u32::from_bytes(x0))),
|
||||
f32::from_bits(u32::from_le(u32::from_bytes(x1))),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
pub static ref F32F32F32: Vec<(f32, f32, f32)> = {
|
||||
let bytes = include_bytes!("../../bin/input/f32f32f32");
|
||||
|
||||
bytes
|
||||
.exact_chunks(12)
|
||||
.map(|chunk| {
|
||||
let mut x0 = [0; 4];
|
||||
let mut x1 = [0; 4];
|
||||
let mut x2 = [0; 4];
|
||||
x0.copy_from_slice(&chunk[..4]);
|
||||
x1.copy_from_slice(&chunk[4..8]);
|
||||
x2.copy_from_slice(&chunk[8..]);
|
||||
|
||||
(
|
||||
f32::from_bits(u32::from_le(u32::from_bytes(x0))),
|
||||
f32::from_bits(u32::from_le(u32::from_bytes(x1))),
|
||||
f32::from_bits(u32::from_le(u32::from_bytes(x2))),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
pub static ref F32I32: Vec<(f32, i32)> = {
|
||||
let bytes = include_bytes!("../../bin/input/f32i16");
|
||||
|
||||
bytes
|
||||
.exact_chunks(6)
|
||||
.map(|chunk| {
|
||||
let mut x0 = [0; 4];
|
||||
let mut x1 = [0; 2];
|
||||
x0.copy_from_slice(&chunk[..4]);
|
||||
x1.copy_from_slice(&chunk[4..]);
|
||||
|
||||
(
|
||||
f32::from_bits(u32::from_le(u32::from_bytes(x0))),
|
||||
i16::from_le(i16::from_bytes(x1)) as i32,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
pub static ref F64: Vec<f64> = {
|
||||
let bytes = include_bytes!("../../bin/input/f64");
|
||||
|
||||
bytes
|
||||
.exact_chunks(8)
|
||||
.map(|chunk| {
|
||||
let mut buf = [0; 8];
|
||||
buf.copy_from_slice(chunk);
|
||||
f64::from_bits(u64::from_le(u64::from_bytes(buf)))
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
pub static ref F64F64: Vec<(f64, f64)> = {
|
||||
let bytes = include_bytes!("../../bin/input/f64f64");
|
||||
|
||||
bytes
|
||||
.exact_chunks(16)
|
||||
.map(|chunk| {
|
||||
let mut x0 = [0; 8];
|
||||
let mut x1 = [0; 8];
|
||||
x0.copy_from_slice(&chunk[..8]);
|
||||
x1.copy_from_slice(&chunk[8..]);
|
||||
|
||||
(
|
||||
f64::from_bits(u64::from_le(u64::from_bytes(x0))),
|
||||
f64::from_bits(u64::from_le(u64::from_bytes(x1))),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
pub static ref F64F64F64: Vec<(f64, f64, f64)> = {
|
||||
let bytes = include_bytes!("../../bin/input/f64f64f64");
|
||||
|
||||
bytes
|
||||
.exact_chunks(24)
|
||||
.map(|chunk| {
|
||||
let mut x0 = [0; 8];
|
||||
let mut x1 = [0; 8];
|
||||
let mut x2 = [0; 8];
|
||||
x0.copy_from_slice(&chunk[..8]);
|
||||
x1.copy_from_slice(&chunk[8..16]);
|
||||
x2.copy_from_slice(&chunk[16..]);
|
||||
|
||||
(
|
||||
f64::from_bits(u64::from_le(u64::from_bytes(x0))),
|
||||
f64::from_bits(u64::from_le(u64::from_bytes(x1))),
|
||||
f64::from_bits(u64::from_le(u64::from_bytes(x2))),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
pub static ref F64I32: Vec<(f64, i32)> = {
|
||||
let bytes = include_bytes!("../../bin/input/f64i16");
|
||||
|
||||
bytes
|
||||
.exact_chunks(10)
|
||||
.map(|chunk| {
|
||||
let mut x0 = [0; 8];
|
||||
let mut x1 = [0; 2];
|
||||
x0.copy_from_slice(&chunk[..8]);
|
||||
x1.copy_from_slice(&chunk[8..]);
|
||||
|
||||
(
|
||||
f64::from_bits(u64::from_le(u64::from_bytes(x0))),
|
||||
i16::from_le(i16::from_bytes(x1)) as i32,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! f32 {
|
||||
($lib:expr, $($fun:ident),+) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fun() {
|
||||
let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun)))
|
||||
.exact_chunks(4)
|
||||
.map(|chunk| {
|
||||
let mut buf = [0; 4];
|
||||
buf.copy_from_slice(chunk);
|
||||
f32::from_bits(u32::from_le(u32::from_bytes(buf)))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for (input, expected) in $crate::F32.iter().zip(&expected) {
|
||||
if let Ok(output) = panic::catch_unwind(|| libm::$fun(*input)) {
|
||||
if let Err(error) = libm::_eqf(output, *expected) {
|
||||
panic!(
|
||||
"INPUT: {:#x}, OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}",
|
||||
input.to_bits(),
|
||||
output.to_bits(),
|
||||
expected.to_bits(),
|
||||
error
|
||||
);
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"INPUT: {:#x}, OUTPUT: PANIC!, EXPECTED: {:#x}",
|
||||
input.to_bits(),
|
||||
expected.to_bits()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! f32f32 {
|
||||
($lib:expr, $($fun:ident),+) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fun() {
|
||||
let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun)))
|
||||
.exact_chunks(4)
|
||||
.map(|chunk| {
|
||||
let mut buf = [0; 4];
|
||||
buf.copy_from_slice(chunk);
|
||||
f32::from_bits(u32::from_le(u32::from_bytes(buf)))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for ((i0, i1), expected) in $crate::F32F32.iter().zip(&expected) {
|
||||
if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) {
|
||||
if let Err(error) = libm::_eqf(output, *expected) {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}",
|
||||
i0.to_bits(),
|
||||
i1.to_bits(),
|
||||
output.to_bits(),
|
||||
expected.to_bits(),
|
||||
error
|
||||
);
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}",
|
||||
i0.to_bits(),
|
||||
i1.to_bits(),
|
||||
expected.to_bits()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! f32f32f32 {
|
||||
($lib:expr, $($fun:ident),+) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fun() {
|
||||
let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun)))
|
||||
.exact_chunks(4)
|
||||
.map(|chunk| {
|
||||
let mut buf = [0; 4];
|
||||
buf.copy_from_slice(chunk);
|
||||
f32::from_bits(u32::from_le(u32::from_bytes(buf)))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for ((i0, i1, i2), expected) in $crate::F32F32F32.iter().zip(&expected) {
|
||||
if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1, *i2)) {
|
||||
if let Err(error) = libm::_eqf(output, *expected) {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}",
|
||||
i0.to_bits(),
|
||||
i1.to_bits(),
|
||||
i2.to_bits(),
|
||||
output.to_bits(),
|
||||
expected.to_bits(),
|
||||
error
|
||||
);
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}",
|
||||
i0.to_bits(),
|
||||
i1.to_bits(),
|
||||
expected.to_bits()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! f32i32 {
|
||||
($lib:expr, $($fun:ident),+) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fun() {
|
||||
let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun)))
|
||||
.exact_chunks(4)
|
||||
.map(|chunk| {
|
||||
let mut buf = [0; 4];
|
||||
buf.copy_from_slice(chunk);
|
||||
f32::from_bits(u32::from_le(u32::from_bytes(buf)))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for ((i0, i1), expected) in $crate::F32I32.iter().zip(&expected) {
|
||||
if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) {
|
||||
if let Err(error) = libm::_eqf(output, *expected) {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}",
|
||||
i0.to_bits(),
|
||||
i1,
|
||||
output.to_bits(),
|
||||
expected.to_bits(),
|
||||
error
|
||||
);
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}",
|
||||
i0.to_bits(),
|
||||
i1,
|
||||
expected.to_bits()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! f64 {
|
||||
($lib:expr, $($fun:ident),+) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fun() {
|
||||
let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun)))
|
||||
.exact_chunks(8)
|
||||
.map(|chunk| {
|
||||
let mut buf = [0; 8];
|
||||
buf.copy_from_slice(chunk);
|
||||
f64::from_bits(u64::from_le(u64::from_bytes(buf)))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for (input, expected) in shared::F64.iter().zip(&expected) {
|
||||
if let Ok(output) = panic::catch_unwind(|| libm::$fun(*input)) {
|
||||
if let Err(error) = libm::_eq(output, *expected) {
|
||||
panic!(
|
||||
"INPUT: {:#x}, OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}",
|
||||
input.to_bits(),
|
||||
output.to_bits(),
|
||||
expected.to_bits(),
|
||||
error
|
||||
);
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"INPUT: {:#x}, OUTPUT: PANIC!, EXPECTED: {:#x}",
|
||||
input.to_bits(),
|
||||
expected.to_bits()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! f64f64 {
|
||||
($lib:expr, $($fun:ident),+) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fun() {
|
||||
let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun)))
|
||||
.exact_chunks(8)
|
||||
.map(|chunk| {
|
||||
let mut buf = [0; 8];
|
||||
buf.copy_from_slice(chunk);
|
||||
f64::from_bits(u64::from_le(u64::from_bytes(buf)))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for ((i0, i1), expected) in shared::F64F64.iter().zip(&expected) {
|
||||
if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) {
|
||||
if let Err(error) = libm::_eq(output, *expected) {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}",
|
||||
i0.to_bits(),
|
||||
i1.to_bits(),
|
||||
output.to_bits(),
|
||||
expected.to_bits(),
|
||||
error
|
||||
);
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}",
|
||||
i0.to_bits(),
|
||||
i1.to_bits(),
|
||||
expected.to_bits()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! f64f64f64 {
|
||||
($lib:expr, $($fun:ident),+) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fun() {
|
||||
let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun)))
|
||||
.exact_chunks(8)
|
||||
.map(|chunk| {
|
||||
let mut buf = [0; 8];
|
||||
buf.copy_from_slice(chunk);
|
||||
f64::from_bits(u64::from_le(u64::from_bytes(buf)))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for ((i0, i1, i2), expected) in shared::F64F64F64.iter().zip(&expected) {
|
||||
if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1, *i2)) {
|
||||
if let Err(error) = libm::_eq(output, *expected) {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}",
|
||||
i0.to_bits(),
|
||||
i1.to_bits(),
|
||||
i2.to_bits(),
|
||||
output.to_bits(),
|
||||
expected.to_bits(),
|
||||
error
|
||||
);
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}",
|
||||
i0.to_bits(),
|
||||
i1.to_bits(),
|
||||
expected.to_bits()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! f64i32 {
|
||||
($lib:expr, $($fun:ident),+) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fun() {
|
||||
let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun)))
|
||||
.exact_chunks(8)
|
||||
.map(|chunk| {
|
||||
let mut buf = [0; 8];
|
||||
buf.copy_from_slice(chunk);
|
||||
f64::from_bits(u64::from_le(u64::from_bytes(buf)))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for ((i0, i1), expected) in shared::F64I32.iter().zip(&expected) {
|
||||
if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) {
|
||||
if let Err(error) = libm::_eq(output, *expected) {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}",
|
||||
i0.to_bits(),
|
||||
i1,
|
||||
output.to_bits(),
|
||||
expected.to_bits(),
|
||||
error
|
||||
);
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}",
|
||||
i0.to_bits(),
|
||||
i1,
|
||||
expected.to_bits()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
|
@ -625,3 +625,6 @@ mod private {
|
|||
impl Sealed for f32 {}
|
||||
impl Sealed for f64 {}
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature = "musl-reference-tests"))]
|
||||
include!(concat!(env!("OUT_DIR"), "/musl-tests.rs"));
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ fn r(z: f64) -> f64 {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn acos(x: f64) -> f64 {
|
||||
let x1p_120f = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ -120
|
||||
let z: f64;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ fn r(z: f32) -> f32 {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn acosf(x: f32) -> f32 {
|
||||
let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120)
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ fn comp_r(z: f64) -> f64 {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn asin(mut x: f64) -> f64 {
|
||||
let z: f64;
|
||||
let r: f64;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ fn r(z: f32) -> f32 {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn asinf(mut x: f32) -> f32 {
|
||||
let x1p_120 = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ (-120)
|
||||
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ const AT: [f64; 11] = [
|
|||
];
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn atan(x: f64) -> f64 {
|
||||
let mut x = x;
|
||||
let mut ix = (x.to_bits() >> 32) as u32;
|
||||
|
|
@ -147,7 +148,8 @@ mod tests {
|
|||
(-3.0_f64.sqrt() / 3.0, -f64::consts::FRAC_PI_6),
|
||||
(-1.0, -f64::consts::FRAC_PI_4),
|
||||
(-3.0_f64.sqrt(), -f64::consts::FRAC_PI_3),
|
||||
].iter()
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
assert!(
|
||||
(atan(*input) - answer) / answer < 1e-5,
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ const PI: f64 = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */
|
|||
const PI_LO: f64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn atan2(y: f64, x: f64) -> f64 {
|
||||
if x.is_nan() || y.is_nan() {
|
||||
return x + y;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */
|
|||
const PI_LO: f32 = -8.7422776573e-08; /* 0xb3bbbd2e */
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn atan2f(y: f32, x: f32) -> f32 {
|
||||
if x.is_nan() || y.is_nan() {
|
||||
return x + y;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ const A_T: [f32; 5] = [
|
|||
];
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn atanf(mut x: f32) -> f32 {
|
||||
let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120)
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ const P3: f64 = -0.758397934778766047437; /* 0xbfe844cb, 0xbee751d9 */
|
|||
const P4: f64 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn cbrt(x: f64) -> f64 {
|
||||
let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ const B1: u32 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */
|
|||
const B2: u32 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn cbrtf(x: f32) -> f32 {
|
||||
let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use core::f64;
|
|||
const TOINT: f64 = 1. / f64::EPSILON;
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn ceil(x: f64) -> f64 {
|
||||
// On wasm32 we know that LLVM's intrinsic will compile to an optimized
|
||||
// `f64.ceil` native instruction, so we can leverage this for both code size
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use core::f32;
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn ceilf(x: f32) -> f32 {
|
||||
// On wasm32 we know that LLVM's intrinsic will compile to an optimized
|
||||
// `f32.ceil` native instruction, so we can leverage this for both code size
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ use super::{k_cos, k_sin, rem_pio2};
|
|||
// TRIG(x) returns trig(x) nearly rounded
|
||||
//
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn cos(x: f64) -> f64 {
|
||||
let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff;
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ const C3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */
|
|||
const C4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn cosf(x: f32) -> f32 {
|
||||
let x64 = x as f64;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use super::expm1;
|
|||
use super::k_expo2;
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn cosh(mut x: f64) -> f64 {
|
||||
/* |x| */
|
||||
let mut ix = x.to_bits();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use super::expm1f;
|
|||
use super::k_expo2f;
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn coshf(mut x: f32) -> f32 {
|
||||
let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120
|
||||
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ const P4: f64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */
|
|||
const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn exp(mut x: f64) -> f64 {
|
||||
let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023
|
||||
let x1p_149 = f64::from_bits(0x36a0000000000000); // 0x1p-149 === 2 ^ -149
|
||||
|
|
|
|||
|
|
@ -319,6 +319,7 @@ static TBL: [u64; TBLSIZE * 2] = [
|
|||
// Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library
|
||||
// for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991).
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn exp2(mut x: f64) -> f64 {
|
||||
let redux = f64::from_bits(0x4338000000000000) / TBLSIZE as f64;
|
||||
let p1 = f64::from_bits(0x3fe62e42fefa39ef);
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ static EXP2FT: [u64; TBLSIZE] = [
|
|||
// Tang, P. Table-driven Implementation of the Exponential Function
|
||||
// in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989).
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn exp2f(mut x: f32) -> f32 {
|
||||
let redux = f32::from_bits(0x4b400000) / TBLSIZE as f32;
|
||||
let p1 = f32::from_bits(0x3f317218);
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@ const P1: f32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */
|
|||
const P2: f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn expf(mut x: f32) -> f32 {
|
||||
let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127
|
||||
let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */
|
||||
|
||||
let mut hx = x.to_bits();
|
||||
let sign = (hx >> 31) as i32; /* sign bit of x */
|
||||
let signb: bool = sign != 0;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ const Q4: f64 = 4.00821782732936239552e-06; /* 3ED0CFCA 86E65239 */
|
|||
const Q5: f64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn expm1(mut x: f64) -> f64 {
|
||||
let hi: f64;
|
||||
let lo: f64;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ const Q1: f32 = -3.3333212137e-2; /* -0x888868.0p-28 */
|
|||
const Q2: f32 = 1.5807170421e-3; /* 0xcf3010.0p-33 */
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn expm1f(mut x: f32) -> f32 {
|
||||
let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use super::{combine_words, exp};
|
|||
|
||||
/* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn expo2(x: f64) -> f64 {
|
||||
/* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */
|
||||
const K: i32 = 2043;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use core::u64;
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn fabs(x: f64) -> f64 {
|
||||
// On wasm32 we know that LLVM's intrinsic will compile to an optimized
|
||||
// `f64.abs` native instruction, so we can leverage this for both code size
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn fabsf(x: f32) -> f32 {
|
||||
// On wasm32 we know that LLVM's intrinsic will compile to an optimized
|
||||
// `f32.abs` native instruction, so we can leverage this for both code size
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use core::f64;
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn fdim(x: f64, y: f64) -> f64 {
|
||||
if x.is_nan() {
|
||||
x
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use core::f32;
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn fdimf(x: f32, y: f32) -> f32 {
|
||||
if x.is_nan() {
|
||||
x
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use core::f64;
|
|||
const TOINT: f64 = 1. / f64::EPSILON;
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn floor(x: f64) -> f64 {
|
||||
// On wasm32 we know that LLVM's intrinsic will compile to an optimized
|
||||
// `f64.floor` native instruction, so we can leverage this for both code size
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use core::f32;
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn floorf(x: f32) -> f32 {
|
||||
// On wasm32 we know that LLVM's intrinsic will compile to an optimized
|
||||
// `f32.floor` native instruction, so we can leverage this for both code size
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ fn mul(x: u64, y: u64) -> (u64, u64) {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn fma(x: f64, y: f64, z: f64) -> f64 {
|
||||
let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63
|
||||
let x0_ffffff8p_63 = f64::from_bits(0x3bfffffff0000000); // 0x0.ffffff8p-63
|
||||
|
|
@ -165,13 +166,13 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 {
|
|||
}
|
||||
if r == c {
|
||||
/* min normal after rounding, underflow depends
|
||||
on arch behaviour which can be imitated by
|
||||
a double to float conversion */
|
||||
on arch behaviour which can be imitated by
|
||||
a double to float conversion */
|
||||
let fltmin: f32 = (x0_ffffff8p_63 * f32::MIN_POSITIVE as f64 * r) as f32;
|
||||
return f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * fltmin as f64;
|
||||
}
|
||||
/* one bit is lost when scaled, add another top bit to
|
||||
only round once at conversion if it is inexact */
|
||||
only round once at conversion if it is inexact */
|
||||
if (rhi << 53) != 0 {
|
||||
i = (rhi >> 1 | (rhi & 1) | 1 << 62) as i64;
|
||||
if sign != 0 {
|
||||
|
|
@ -181,7 +182,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 {
|
|||
r = 2. * r - c; /* remove top bit */
|
||||
|
||||
/* raise underflow portably, such that it
|
||||
cannot be optimized away */
|
||||
cannot be optimized away */
|
||||
{
|
||||
let tiny: f64 = f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * r;
|
||||
r += (tiny * tiny) * (r - r);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ use super::fenv::{
|
|||
* rounding occurs.
|
||||
*/
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 {
|
||||
let xy: f64;
|
||||
let mut result: f64;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use core::u64;
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn fmod(x: f64, y: f64) -> f64 {
|
||||
let mut uxi = x.to_bits();
|
||||
let mut uyi = y.to_bits();
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use core::f32;
|
|||
use core::u32;
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn fmodf(x: f32, y: f32) -> f32 {
|
||||
let mut uxi = x.to_bits();
|
||||
let mut uyi = y.to_bits();
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ fn sq(x: f64) -> (f64, f64) {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn hypot(mut x: f64, mut y: f64) -> f64 {
|
||||
let x1p700 = f64::from_bits(0x6bb0000000000000); // 0x1p700 === 2 ^ 700
|
||||
let x1p_700 = f64::from_bits(0x1430000000000000); // 0x1p-700 === 2 ^ -700
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use core::f32;
|
|||
use super::sqrtf;
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn hypotf(mut x: f32, mut y: f32) -> f32 {
|
||||
let x1p90 = f32::from_bits(0x6c800000); // 0x1p90f === 2 ^ 90
|
||||
let x1p_90 = f32::from_bits(0x12800000); // 0x1p-90f === 2 ^ -90
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
|
|||
// under FreeBSD, so don't pessimize things by forcibly clipping
|
||||
// any extra precision in w.
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn k_cos(x: f64, y: f64) -> f64 {
|
||||
let z = x * x;
|
||||
let w = z * z;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ const C2: f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */
|
|||
const C3: f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn k_cosf(x: f64) -> f32 {
|
||||
let z = x * x;
|
||||
let w = z * z;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ const K: i32 = 2043;
|
|||
|
||||
/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub(crate) fn k_expo2(x: f64) -> f64 {
|
||||
let k_ln2 = f64::from_bits(0x40962066151add8b);
|
||||
/* note that k is odd and scale*scale overflows */
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ const K: i32 = 235;
|
|||
|
||||
/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn k_expo2f(x: f32) -> f32 {
|
||||
let k_ln2 = f32::from_bits(0x4322e3bc);
|
||||
/* note that k is odd and scale*scale overflows */
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */
|
|||
// then 3 2
|
||||
// sin(x) = x + (S1*x + (x *(r-y/2)+y))
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn k_sin(x: f64, y: f64, iy: i32) -> f64 {
|
||||
let z = x * x;
|
||||
let w = z * z;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ const S3: f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */
|
|||
const S4: f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn k_sinf(x: f64) -> f32 {
|
||||
let z = x * x;
|
||||
let w = z * z;
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ const PIO4: f64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */
|
|||
const PIO4_LO: f64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 {
|
||||
let hx = (f64::to_bits(x) >> 32) as u32;
|
||||
let big = (hx & 0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ const T: [f64; 6] = [
|
|||
];
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn k_tanf(x: f64, odd: bool) -> f32 {
|
||||
let z = x * x;
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */
|
|||
const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn log(mut x: f64) -> f64 {
|
||||
let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */
|
|||
const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn log10(mut x: f64) -> f64 {
|
||||
let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */
|
|||
const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn log10f(mut x: f32) -> f32 {
|
||||
let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */
|
|||
const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn log1p(x: f64) -> f64 {
|
||||
let mut ui: u64 = x.to_bits();
|
||||
let hfsq: f64;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */
|
|||
const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn log1pf(x: f32) -> f32 {
|
||||
let mut ui: u32 = x.to_bits();
|
||||
let hfsq: f32;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */
|
|||
const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn log2(mut x: f64) -> f64 {
|
||||
let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */
|
|||
const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn log2f(mut x: f32) -> f32 {
|
||||
let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */
|
|||
const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn logf(mut x: f32) -> f32 {
|
||||
let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25
|
||||
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ const IVLN2_H: f64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/l
|
|||
const IVLN2_L: f64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn pow(x: f64, y: f64) -> f64 {
|
||||
let t1: f64;
|
||||
let t2: f64;
|
||||
|
|
@ -261,7 +262,7 @@ pub fn pow(x: f64, y: f64) -> f64 {
|
|||
}
|
||||
|
||||
/* now |1-x| is TINY <= 2**-20, suffice to compute
|
||||
log(x) by x-x^2/2+x^3/3-x^4/4 */
|
||||
log(x) by x-x^2/2+x^3/3-x^4/4 */
|
||||
let t: f64 = ax - 1.0; /* t has 20 trailing zeros */
|
||||
let w: f64 = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25));
|
||||
let u: f64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ const IVLN2_H: f32 = 1.4426879883e+00;
|
|||
const IVLN2_L: f32 = 7.0526075433e-06;
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn powf(x: f32, y: f32) -> f32 {
|
||||
let mut z: f32;
|
||||
let mut ax: f32;
|
||||
|
|
@ -197,7 +198,7 @@ pub fn powf(x: f32, y: f32) -> f32 {
|
|||
}
|
||||
|
||||
/* now |1-x| is TINY <= 2**-20, suffice to compute
|
||||
log(x) by x-x^2/2+x^3/3-x^4/4 */
|
||||
log(x) by x-x^2/2+x^3/3-x^4/4 */
|
||||
t = ax - 1.; /* t has 20 trailing zeros */
|
||||
w = (t * t) * (0.5 - t * (0.333333333333 - t * 0.25));
|
||||
u = IVLN2_H * t; /* IVLN2_H has 16 sig. bits */
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
// ====================================================
|
||||
//
|
||||
// Optimized by Bruce D. Evans. */
|
||||
|
||||
use super::rem_pio2_large;
|
||||
|
||||
// #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1
|
||||
|
|
@ -43,6 +42,7 @@ const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */
|
|||
//
|
||||
// caller must handle the case when reduction is not needed: |x| ~<= pi/4 */
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn rem_pio2(x: f64) -> (i32, f64, f64) {
|
||||
let x1p24 = f64::from_bits(0x4170000000000000);
|
||||
|
||||
|
|
|
|||
|
|
@ -223,6 +223,7 @@ const PIO2: [f64; 8] = [
|
|||
/// more accurately, = 0 mod 8 ). Thus the number of operations are
|
||||
/// independent of the exponent of the input.
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 {
|
||||
let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24
|
||||
let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24)
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ const PIO2_1T: f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */
|
|||
/// use double precision for everything except passing x
|
||||
/// use __rem_pio2_large() for large x
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn rem_pio2f(x: f32) -> (i32, f64) {
|
||||
let x64 = x as f64;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use core::f64;
|
|||
const TOINT: f64 = 1.0 / f64::EPSILON;
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn round(mut x: f64) -> f64 {
|
||||
let (f, i) = (x, x.to_bits());
|
||||
let e: u64 = i >> 52 & 0x7ff;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use core::f32;
|
|||
const TOINT: f32 = 1.0 / f32::EPSILON;
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn roundf(mut x: f32) -> f32 {
|
||||
let i = x.to_bits();
|
||||
let e: u32 = i >> 23 & 0xff;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn scalbn(x: f64, mut n: i32) -> f64 {
|
||||
let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023
|
||||
let x1p53 = f64::from_bits(0x4340000000000000); // 0x1p53 === 2 ^ 53
|
||||
|
|
@ -18,7 +19,7 @@ pub fn scalbn(x: f64, mut n: i32) -> f64 {
|
|||
}
|
||||
} else if n < -1022 {
|
||||
/* make sure final n < -53 to avoid double
|
||||
rounding in the subnormal range */
|
||||
rounding in the subnormal range */
|
||||
y *= x1p_1022 * x1p53;
|
||||
n += 1022 - 53;
|
||||
if n < -1022 {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#[inline]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn scalbnf(mut x: f32, mut n: i32) -> f32 {
|
||||
let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127
|
||||
let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue