initial commit
This commit is contained in:
commit
a043c38e41
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
**/*.rs.bk
|
||||
.#*
|
||||
/target
|
||||
/tests
|
||||
Cargo.lock
|
7
Cargo.toml
Normal file
7
Cargo.toml
Normal file
@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "libm"
|
||||
version = "0.1.0"
|
||||
authors = ["Jorge Aparicio <jorge@japaric.io>"]
|
||||
|
||||
[workspace]
|
||||
members = ["test-generator"]
|
201
LICENSE-APACHE
Normal file
201
LICENSE-APACHE
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
25
LICENSE-MIT
Normal file
25
LICENSE-MIT
Normal file
@ -0,0 +1,25 @@
|
||||
Copyright (c) 2018 Jorge Aparicio
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
111
README.md
Normal file
111
README.md
Normal file
@ -0,0 +1,111 @@
|
||||
# `libm`
|
||||
|
||||
A port of [MUSL]'s libm to Rust.
|
||||
|
||||
[MUSL]: https://www.musl-libc.org/
|
||||
|
||||
## Testing
|
||||
|
||||
The test suite of this crate can only be run on x86_64 Linux systems.
|
||||
|
||||
```
|
||||
$ # The test suite depends on the `cross` tool so install it if you don't have it
|
||||
$ cargo install cross
|
||||
|
||||
$ # and the `cross` tool requires docker to be running
|
||||
$ systemctl start docker
|
||||
|
||||
$ # execute the test suite for the x86_64 target
|
||||
$ TARGET=x86_64-unknown-linux-gnu bash ci/script.sh
|
||||
|
||||
$ # execute the test suite for the ARMv7 target
|
||||
$ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
- Pick your favorite math function from the list below.
|
||||
- Look for the C implementation of the function in the [MUSL source code][src].
|
||||
- Copy paste the C code into a Rust file in the `src` directory and adjust `src/lib.rs` accordingly.
|
||||
- Run `cargo watch check` and fix the compiler errors.
|
||||
- If you can, run the test suite locally. If you can't, no problem! Your PR will be tested
|
||||
automatically.
|
||||
- Send us a pull request!
|
||||
- :tada:
|
||||
|
||||
### Notes
|
||||
|
||||
- To reinterpret a float as an integer use the `to_bits` method. The MUSL code uses the
|
||||
`GET_FLOAT_WORD` macro, or a union, to do this operation.
|
||||
|
||||
- To reinterpret an integer as a float use the `f32::from_bits` constructor. The MUSL code uses the
|
||||
`SET_FLOAT_WORD` macro, or a union, to do this operation.
|
||||
|
||||
- Rust code panics on arithmetic overflows when not optimized. You may need to use the [`Wrapping`]
|
||||
newtype to avoid this problem.
|
||||
|
||||
[src]: https://git.musl-libc.org/cgit/musl/tree/src/math
|
||||
[`Wrapping`]: https://doc.rust-lang.org/std/num/struct.Wrapping.html
|
||||
|
||||
## Progress
|
||||
|
||||
### Functions wanted by the wasm WG
|
||||
|
||||
cf. [rustwasm/team#84](https://github.com/rustwasm/team/issues/84).
|
||||
|
||||
- [ ] acos
|
||||
- [ ] asin
|
||||
- [ ] atan
|
||||
- [ ] atan2
|
||||
- [ ] cbrt
|
||||
- [ ] cos
|
||||
- [ ] cosf
|
||||
- [ ] cosh
|
||||
- [ ] exp
|
||||
- [ ] exp2
|
||||
- [ ] exp2f
|
||||
- [ ] expf
|
||||
- [ ] expm1
|
||||
- [ ] fma
|
||||
- [ ] fmaf
|
||||
- [ ] fmod
|
||||
- [ ] fmodf
|
||||
- [ ] hypot
|
||||
- [ ] log
|
||||
- [ ] log10
|
||||
- [ ] log10f
|
||||
- [ ] log1p
|
||||
- [ ] log2
|
||||
- [ ] log2f
|
||||
- [ ] logf
|
||||
- [ ] pow
|
||||
- [x] powf
|
||||
- [ ] round
|
||||
- [ ] roundf
|
||||
- [ ] sin
|
||||
- [ ] sinf
|
||||
- [ ] sinh
|
||||
- [ ] tan
|
||||
- [ ] tanh
|
||||
|
||||
### Other functions
|
||||
|
||||
- [x] fabsf
|
||||
- [x] scalbnf
|
||||
- [x] sqrtf
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of
|
||||
|
||||
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||
http://www.apache.org/licenses/LICENSE-2.0)
|
||||
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the
|
||||
work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
|
||||
additional terms or conditions.
|
12
ci/script.sh
Normal file
12
ci/script.sh
Normal file
@ -0,0 +1,12 @@
|
||||
set -euxo pipefail
|
||||
|
||||
main() {
|
||||
cargo run --package test-generator --target x86_64-unknown-linux-musl
|
||||
if hash cargo-fmt; then
|
||||
# nicer syntax error messages (if any)
|
||||
cargo fmt
|
||||
fi
|
||||
cross test --target $TARGET --release
|
||||
}
|
||||
|
||||
main
|
3
src/fabsf.rs
Normal file
3
src/fabsf.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub fn fabsf(x: f32) -> f32 {
|
||||
f32::from_bits(x.to_bits() & 0x7fffffff)
|
||||
}
|
12
src/lib.rs
Normal file
12
src/lib.rs
Normal file
@ -0,0 +1,12 @@
|
||||
#![deny(warnings)]
|
||||
#![no_std]
|
||||
|
||||
mod fabsf;
|
||||
mod powf;
|
||||
mod scalbnf;
|
||||
mod sqrtf;
|
||||
|
||||
pub use fabsf::fabsf;
|
||||
pub use powf::powf;
|
||||
pub use scalbnf::scalbnf;
|
||||
pub use sqrtf::sqrtf;
|
326
src/powf.rs
Normal file
326
src/powf.rs
Normal file
@ -0,0 +1,326 @@
|
||||
use {scalbnf, sqrtf};
|
||||
|
||||
const BP: [f32; 2] = [1.0, 1.5];
|
||||
const DP_H: [f32; 2] = [0.0, 5.84960938e-01]; /* 0x3f15c000 */
|
||||
const DP_L: [f32; 2] = [0.0, 1.56322085e-06]; /* 0x35d1cfdc */
|
||||
const TWO24: f32 = 16777216.0; /* 0x4b800000 */
|
||||
const HUGE: f32 = 1.0e30;
|
||||
const TINY: f32 = 1.0e-30;
|
||||
const L1: f32 = 6.0000002384e-01; /* 0x3f19999a */
|
||||
const L2: f32 = 4.2857143283e-01; /* 0x3edb6db7 */
|
||||
const L3: f32 = 3.3333334327e-01; /* 0x3eaaaaab */
|
||||
const L4: f32 = 2.7272811532e-01; /* 0x3e8ba305 */
|
||||
const L5: f32 = 2.3066075146e-01; /* 0x3e6c3255 */
|
||||
const L6: f32 = 2.0697501302e-01; /* 0x3e53f142 */
|
||||
const P1: f32 = 1.6666667163e-01; /* 0x3e2aaaab */
|
||||
const P2: f32 = -2.7777778450e-03; /* 0xbb360b61 */
|
||||
const P3: f32 = 6.6137559770e-05; /* 0x388ab355 */
|
||||
const P4: f32 = -1.6533901999e-06; /* 0xb5ddea0e */
|
||||
const P5: f32 = 4.1381369442e-08; /* 0x3331bb4c */
|
||||
const LG2: f32 = 6.9314718246e-01; /* 0x3f317218 */
|
||||
const LG2_H: f32 = 6.93145752e-01; /* 0x3f317200 */
|
||||
const LG2_L: f32 = 1.42860654e-06; /* 0x35bfbe8c */
|
||||
const OVT: f32 = 4.2995665694e-08; /* -(128-log2(ovfl+.5ulp)) */
|
||||
const CP: f32 = 9.6179670095e-01; /* 0x3f76384f =2/(3ln2) */
|
||||
const CP_H: f32 = 9.6191406250e-01; /* 0x3f764000 =12b cp */
|
||||
const CP_L: f32 = -1.1736857402e-04; /* 0xb8f623c6 =tail of cp_h */
|
||||
const IVLN2: f32 = 1.4426950216e+00;
|
||||
const IVLN2_H: f32 = 1.4426879883e+00;
|
||||
const IVLN2_L: f32 = 7.0526075433e-06;
|
||||
|
||||
pub fn powf(x: f32, y: f32) -> f32 {
|
||||
let mut z: f32;
|
||||
let mut ax: f32;
|
||||
let z_h: f32;
|
||||
let z_l: f32;
|
||||
let mut p_h: f32;
|
||||
let mut p_l: f32;
|
||||
let y1: f32;
|
||||
let mut t1: f32;
|
||||
let t2: f32;
|
||||
let mut r: f32;
|
||||
let s: f32;
|
||||
let mut sn: f32;
|
||||
let mut t: f32;
|
||||
let mut u: f32;
|
||||
let mut v: f32;
|
||||
let mut w: f32;
|
||||
let i: i32;
|
||||
let mut j: i32;
|
||||
let mut k: i32;
|
||||
let mut yisint: i32;
|
||||
let mut n: i32;
|
||||
let hx: i32;
|
||||
let hy: i32;
|
||||
let mut ix: i32;
|
||||
let iy: i32;
|
||||
let mut is: i32;
|
||||
|
||||
hx = x.to_bits() as i32;
|
||||
hy = y.to_bits() as i32;
|
||||
|
||||
ix = hx & 0x7fffffff;
|
||||
iy = hy & 0x7fffffff;
|
||||
|
||||
/* x**0 = 1, even if x is NaN */
|
||||
if iy == 0 {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
/* 1**y = 1, even if y is NaN */
|
||||
if hx == 0x3f800000 {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
/* NaN if either arg is NaN */
|
||||
if ix > 0x7f800000 || iy > 0x7f800000 {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
/* determine if y is an odd int when x < 0
|
||||
* yisint = 0 ... y is not an integer
|
||||
* yisint = 1 ... y is an odd int
|
||||
* yisint = 2 ... y is an even int
|
||||
*/
|
||||
yisint = 0;
|
||||
if hx < 0 {
|
||||
if iy >= 0x4b800000 {
|
||||
yisint = 2; /* even integer y */
|
||||
} else if iy >= 0x3f800000 {
|
||||
k = (iy >> 23) - 0x7f; /* exponent */
|
||||
j = iy >> (23 - k);
|
||||
if (j << (23 - k)) == iy {
|
||||
yisint = 2 - (j & 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* special value of y */
|
||||
if iy == 0x7f800000 {
|
||||
/* y is +-inf */
|
||||
if ix == 0x3f800000 {
|
||||
/* (-1)**+-inf is 1 */
|
||||
return 1.0;
|
||||
} else if ix > 0x3f800000 {
|
||||
/* (|x|>1)**+-inf = inf,0 */
|
||||
return if hy >= 0 { y } else { 0.0 };
|
||||
} else {
|
||||
/* (|x|<1)**+-inf = 0,inf */
|
||||
return if hy >= 0 { 0.0 } else { -y };
|
||||
}
|
||||
}
|
||||
if iy == 0x3f800000 {
|
||||
/* y is +-1 */
|
||||
return if hy >= 0 { x } else { 1.0 / x };
|
||||
}
|
||||
|
||||
if hy == 0x40000000 {
|
||||
/* y is 2 */
|
||||
return x * x;
|
||||
}
|
||||
|
||||
if hy == 0x3f000000 {
|
||||
/* y is 0.5 */
|
||||
if hx >= 0 {
|
||||
/* x >= +0 */
|
||||
return sqrtf(x);
|
||||
}
|
||||
}
|
||||
|
||||
ax = ::fabsf(x);
|
||||
/* special value of x */
|
||||
if ix == 0x7f800000 || ix == 0 || ix == 0x3f800000 {
|
||||
/* x is +-0,+-inf,+-1 */
|
||||
z = ax;
|
||||
if hy < 0 {
|
||||
/* z = (1/|x|) */
|
||||
z = 1.0 / z;
|
||||
}
|
||||
|
||||
if hx < 0 {
|
||||
if ((ix - 0x3f800000) | yisint) == 0 {
|
||||
z = (z - z) / (z - z); /* (-1)**non-int is NaN */
|
||||
} else if yisint == 1 {
|
||||
z = -z; /* (x<0)**odd = -(|x|**odd) */
|
||||
}
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
||||
sn = 1.0; /* sign of result */
|
||||
if hx < 0 {
|
||||
if yisint == 0 {
|
||||
/* (x<0)**(non-int) is NaN */
|
||||
return (x - x) / (x - x);
|
||||
}
|
||||
|
||||
if yisint == 1 {
|
||||
/* (x<0)**(odd int) */
|
||||
sn = -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
/* |y| is HUGE */
|
||||
if iy > 0x4d000000 {
|
||||
/* if |y| > 2**27 */
|
||||
/* over/underflow if x is not close to one */
|
||||
if ix < 0x3f7ffff8 {
|
||||
return if hy < 0 {
|
||||
sn * HUGE * HUGE
|
||||
} else {
|
||||
sn * TINY * TINY
|
||||
};
|
||||
}
|
||||
|
||||
if ix > 0x3f800007 {
|
||||
return if hy > 0 {
|
||||
sn * HUGE * HUGE
|
||||
} else {
|
||||
sn * TINY * TINY
|
||||
};
|
||||
}
|
||||
|
||||
/* now |1-x| is TINY <= 2**-20, suffice to compute
|
||||
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 */
|
||||
v = t * IVLN2_L - w * IVLN2;
|
||||
t1 = u + v;
|
||||
is = t1.to_bits() as i32;
|
||||
t1 = f32::from_bits(is as u32 & 0xfffff000);
|
||||
t2 = v - (t1 - u);
|
||||
} else {
|
||||
let mut s2: f32;
|
||||
let mut s_h: f32;
|
||||
let s_l: f32;
|
||||
let mut t_h: f32;
|
||||
let mut t_l: f32;
|
||||
|
||||
n = 0;
|
||||
/* take care subnormal number */
|
||||
if ix < 0x00800000 {
|
||||
ax *= TWO24;
|
||||
n -= 24;
|
||||
ix = ax.to_bits() as i32;
|
||||
}
|
||||
n += ((ix) >> 23) - 0x7f;
|
||||
j = ix & 0x007fffff;
|
||||
/* determine interval */
|
||||
ix = j | 0x3f800000; /* normalize ix */
|
||||
if j <= 0x1cc471 {
|
||||
/* |x|<sqrt(3/2) */
|
||||
k = 0;
|
||||
} else if j < 0x5db3d7 {
|
||||
/* |x|<sqrt(3) */
|
||||
k = 1;
|
||||
} else {
|
||||
k = 0;
|
||||
n += 1;
|
||||
ix -= 0x00800000;
|
||||
}
|
||||
ax = f32::from_bits(ix as u32);
|
||||
|
||||
/* compute s = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
|
||||
u = ax - BP[k as usize]; /* bp[0]=1.0, bp[1]=1.5 */
|
||||
v = 1.0 / (ax + BP[k as usize]);
|
||||
s = u * v;
|
||||
s_h = s;
|
||||
is = s_h.to_bits() as i32;
|
||||
s_h = f32::from_bits(is as u32 & 0xfffff000);
|
||||
/* t_h=ax+bp[k] High */
|
||||
is = (((ix as u32 >> 1) & 0xfffff000) | 0x20000000) as i32;
|
||||
t_h = f32::from_bits(is as u32 + 0x00400000 + ((k as u32) << 21));
|
||||
t_l = ax - (t_h - BP[k as usize]);
|
||||
s_l = v * ((u - s_h * t_h) - s_h * t_l);
|
||||
/* compute log(ax) */
|
||||
s2 = s * s;
|
||||
r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6)))));
|
||||
r += s_l * (s_h + s);
|
||||
s2 = s_h * s_h;
|
||||
t_h = 3.0 + s2 + r;
|
||||
is = t_h.to_bits() as i32;
|
||||
t_h = f32::from_bits(is as u32 & 0xfffff000);
|
||||
t_l = r - ((t_h - 3.0) - s2);
|
||||
/* u+v = s*(1+...) */
|
||||
u = s_h * t_h;
|
||||
v = s_l * t_h + t_l * s;
|
||||
/* 2/(3log2)*(s+...) */
|
||||
p_h = u + v;
|
||||
is = p_h.to_bits() as i32;
|
||||
p_h = f32::from_bits(is as u32 & 0xfffff000);
|
||||
p_l = v - (p_h - u);
|
||||
z_h = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */
|
||||
z_l = CP_L * p_h + p_l * CP + DP_L[k as usize];
|
||||
/* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */
|
||||
t = n as f32;
|
||||
t1 = ((z_h + z_l) + DP_H[k as usize]) + t;
|
||||
is = t1.to_bits() as i32;
|
||||
t1 = f32::from_bits(is as u32 & 0xfffff000);
|
||||
t2 = z_l - (((t1 - t) - DP_H[k as usize]) - z_h);
|
||||
};
|
||||
|
||||
/* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
|
||||
is = y.to_bits() as i32;
|
||||
y1 = f32::from_bits(is as u32 & 0xfffff000);
|
||||
p_l = (y - y1) * t1 + y * t2;
|
||||
p_h = y1 * t1;
|
||||
z = p_l + p_h;
|
||||
j = z.to_bits() as i32;
|
||||
if j > 0x43000000 {
|
||||
/* if z > 128 */
|
||||
return sn * HUGE * HUGE; /* overflow */
|
||||
} else if j == 0x43000000 {
|
||||
/* if z == 128 */
|
||||
if p_l + OVT > z - p_h {
|
||||
return sn * HUGE * HUGE; /* overflow */
|
||||
}
|
||||
} else if (j & 0x7fffffff) > 0x43160000 {
|
||||
/* z < -150 */
|
||||
// FIXME: check should be (uint32_t)j > 0xc3160000
|
||||
return sn * TINY * TINY; /* underflow */
|
||||
} else if j as u32 == 0xc3160000 {
|
||||
/* z == -150 */
|
||||
if p_l <= z - p_h {
|
||||
return sn * TINY * TINY; /* underflow */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* compute 2**(p_h+p_l)
|
||||
*/
|
||||
i = j & 0x7fffffff;
|
||||
k = (i >> 23) - 0x7f;
|
||||
n = 0;
|
||||
if i > 0x3f000000 {
|
||||
/* if |z| > 0.5, set n = [z+0.5] */
|
||||
n = j + (0x00800000 >> (k + 1));
|
||||
k = ((n & 0x7fffffff) >> 23) - 0x7f; /* new k for n */
|
||||
t = f32::from_bits(n as u32 & !(0x007fffff >> k));
|
||||
n = ((n & 0x007fffff) | 0x00800000) >> (23 - k);
|
||||
if j < 0 {
|
||||
n = -n;
|
||||
}
|
||||
p_h -= t;
|
||||
}
|
||||
t = p_l + p_h;
|
||||
is = t.to_bits() as i32;
|
||||
t = f32::from_bits(is as u32 & 0xffff8000);
|
||||
u = t * LG2_H;
|
||||
v = (p_l - (t - p_h)) * LG2 + t * LG2_L;
|
||||
z = u + v;
|
||||
w = v - (z - u);
|
||||
t = z * z;
|
||||
t1 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5))));
|
||||
r = (z * t1) / (t1 - 2.0) - (w + z * w);
|
||||
z = 1.0 - (r - z);
|
||||
j = z.to_bits() as i32;
|
||||
j += n << 23;
|
||||
if (j >> 23) <= 0 {
|
||||
/* subnormal output */
|
||||
z = scalbnf(z, n);
|
||||
} else {
|
||||
z = f32::from_bits(j as u32);
|
||||
}
|
||||
return sn * z;
|
||||
}
|
34
src/scalbnf.rs
Normal file
34
src/scalbnf.rs
Normal file
@ -0,0 +1,34 @@
|
||||
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
|
||||
let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24
|
||||
|
||||
let mut y: f32 = x;
|
||||
|
||||
if n > 127 {
|
||||
y *= x1p127;
|
||||
n -= 127;
|
||||
if n > 127 {
|
||||
y *= x1p127;
|
||||
n -= 127;
|
||||
if n > 127 {
|
||||
n = 127;
|
||||
}
|
||||
}
|
||||
} else if n < -126 {
|
||||
y *= x1p_126;
|
||||
y *= x1p24;
|
||||
n += 126 - 24;
|
||||
if n < -126 {
|
||||
y *= x1p_126;
|
||||
y *= x1p24;
|
||||
n += 126 - 24;
|
||||
if n < -126 {
|
||||
n = -126;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x = y * f32::from_bits((0x7f + n as u32) << 23);
|
||||
x
|
||||
}
|
83
src/sqrtf.rs
Normal file
83
src/sqrtf.rs
Normal file
@ -0,0 +1,83 @@
|
||||
const TINY: f32 = 1.0e-30;
|
||||
|
||||
pub fn sqrtf(x: f32) -> f32 {
|
||||
let mut z: f32;
|
||||
let sign: i32 = 0x80000000u32 as i32;
|
||||
let mut ix: i32;
|
||||
let mut s: i32;
|
||||
let mut q: i32;
|
||||
let mut m: i32;
|
||||
let mut t: i32;
|
||||
let mut i: i32;
|
||||
let mut r: u32;
|
||||
|
||||
ix = x.to_bits() as i32;
|
||||
|
||||
/* take care of Inf and NaN */
|
||||
if (ix as u32 & 0x7f800000) == 0x7f800000 {
|
||||
return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */
|
||||
}
|
||||
|
||||
/* take care of zero */
|
||||
if ix <= 0 {
|
||||
if (ix & !sign) == 0 {
|
||||
return x; /* sqrt(+-0) = +-0 */
|
||||
}
|
||||
if ix < 0 {
|
||||
return (x - x) / (x - x); /* sqrt(-ve) = sNaN */
|
||||
}
|
||||
}
|
||||
|
||||
/* normalize x */
|
||||
m = ix >> 23;
|
||||
if m == 0 {
|
||||
/* subnormal x */
|
||||
i = 0;
|
||||
while ix & 0x00800000 == 0 {
|
||||
ix <<= 1;
|
||||
i = i + 1;
|
||||
}
|
||||
m -= i - 1;
|
||||
}
|
||||
m -= 127; /* unbias exponent */
|
||||
ix = (ix & 0x007fffff) | 0x00800000;
|
||||
if m & 1 == 1 {
|
||||
/* odd m, double x to make it even */
|
||||
ix += ix;
|
||||
}
|
||||
m >>= 1; /* m = [m/2] */
|
||||
|
||||
/* generate sqrt(x) bit by bit */
|
||||
ix += ix;
|
||||
q = 0;
|
||||
s = 0;
|
||||
r = 0x01000000; /* r = moving bit from right to left */
|
||||
|
||||
while r != 0 {
|
||||
t = s + r as i32;
|
||||
if t <= ix {
|
||||
s = t + r as i32;
|
||||
ix -= t;
|
||||
q += r as i32;
|
||||
}
|
||||
ix += ix;
|
||||
r >>= 1;
|
||||
}
|
||||
|
||||
/* use floating add to find out rounding direction */
|
||||
if ix != 0 {
|
||||
z = 1.0 - TINY; /* raise inexact flag */
|
||||
if z >= 1.0 {
|
||||
z = 1.0 + TINY;
|
||||
if z > 1.0 {
|
||||
q += 2;
|
||||
} else {
|
||||
q += q & 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ix = (q >> 1) + 0x3f000000;
|
||||
ix += m << 23;
|
||||
f32::from_bits(ix as u32)
|
||||
}
|
8
test-generator/Cargo.toml
Normal file
8
test-generator/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "test-generator"
|
||||
version = "0.1.0"
|
||||
authors = ["Jorge Aparicio <jorge@japaric.io>"]
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
rand = "0.5.3"
|
8
test-generator/README.md
Normal file
8
test-generator/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
# `test-generator`
|
||||
|
||||
This is a tool to generate test cases for the `libm` crate.
|
||||
|
||||
The generator randomly creates inputs for each math function, then proceeds to compute the
|
||||
expected output for the given function by running the MUSL *C implementation* of the function and
|
||||
finally it packs the test cases as a Cargo test file. For this reason, this generator **must**
|
||||
always be compiled for the `x86_64-unknown-linux-musl` target.
|
234
test-generator/src/main.rs
Normal file
234
test-generator/src/main.rs
Normal file
@ -0,0 +1,234 @@
|
||||
// NOTE we intentionally avoid using the `quote` crate here because it doesn't work with the
|
||||
// `x86_64-unknown-linux-musl` target.
|
||||
|
||||
// NOTE usually the only thing you need to do to test a new math function is to add it to one of the
|
||||
// macro invocations found in the bottom of this file.
|
||||
|
||||
extern crate rand;
|
||||
|
||||
use std::error::Error;
|
||||
use std::fmt::Write as _0;
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write as _1;
|
||||
use std::{i16, u32, u8};
|
||||
|
||||
use rand::{Rng, SeedableRng, XorShiftRng};
|
||||
|
||||
// Number of test cases to generate
|
||||
const NTESTS: usize = 10_000;
|
||||
|
||||
// TODO tweak this function to generate edge cases (zero, infinity, NaN) more often
|
||||
fn f32(rng: &mut XorShiftRng) -> f32 {
|
||||
let sign = if rng.gen_bool(0.5) { 1 << 31 } else { 0 };
|
||||
let exponent = (rng.gen_range(0, u8::MAX) as u32) << 23;
|
||||
let mantissa = rng.gen_range(0, u32::MAX) & ((1 << 23) - 1);
|
||||
|
||||
f32::from_bits(sign + exponent + mantissa)
|
||||
}
|
||||
|
||||
// fn(f32) -> f32
|
||||
macro_rules! f32_f32 {
|
||||
($($intr:ident,)+) => {
|
||||
fn f32_f32(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
|
||||
// MUSL C implementation of the function to test
|
||||
extern "C" {
|
||||
$(fn $intr(_: f32) -> f32;)+
|
||||
}
|
||||
|
||||
$(
|
||||
let mut cases = String::new();
|
||||
for _ in 0..NTESTS {
|
||||
let inp = f32(rng);
|
||||
let out = unsafe { $intr(inp) };
|
||||
|
||||
let inp = inp.to_bits();
|
||||
let out = out.to_bits();
|
||||
|
||||
write!(cases, "({}, {})", inp, out).unwrap();
|
||||
cases.push(',');
|
||||
}
|
||||
|
||||
let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?;
|
||||
write!(f, "
|
||||
extern crate libm;
|
||||
|
||||
#[test]
|
||||
fn {0}() {{
|
||||
const CASES: &[(u32, u32)] = &[
|
||||
{1}
|
||||
];
|
||||
|
||||
for case in CASES {{
|
||||
let (inp, expected) = *case;
|
||||
|
||||
let outf = libm::{0}(f32::from_bits(inp));
|
||||
let outi = outf.to_bits();
|
||||
|
||||
if !((outf.is_nan() && f32::from_bits(expected).is_nan()) ||
|
||||
outi == expected) {{
|
||||
panic!(
|
||||
\"input: {{}}, output: {{}}, expected: {{}}\",
|
||||
inp,
|
||||
outi,
|
||||
expected,
|
||||
);
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
",
|
||||
stringify!($intr),
|
||||
cases)?;
|
||||
)+
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! f32f32_f32 {
|
||||
($($intr:ident,)+) => {
|
||||
fn f32f32_f32(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
|
||||
extern "C" {
|
||||
$(fn $intr(_: f32, _: f32) -> f32;)+
|
||||
}
|
||||
|
||||
$(
|
||||
let mut cases = String::new();
|
||||
for _ in 0..NTESTS {
|
||||
let i1 = f32(rng);
|
||||
let i2 = f32(rng);
|
||||
let out = unsafe { $intr(i1, i2) };
|
||||
|
||||
let i1 = i1.to_bits();
|
||||
let i2 = i2.to_bits();
|
||||
let out = out.to_bits();
|
||||
|
||||
write!(cases, "(({}, {}), {})", i1, i2, out).unwrap();
|
||||
cases.push(',');
|
||||
}
|
||||
|
||||
let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?;
|
||||
write!(f, "
|
||||
extern crate libm;
|
||||
|
||||
#[test]
|
||||
fn {0}() {{
|
||||
const CASES: &[((u32, u32), u32)] = &[
|
||||
{1}
|
||||
];
|
||||
|
||||
for case in CASES {{
|
||||
let ((i1, i2), expected) = *case;
|
||||
|
||||
let outf = libm::{0}(f32::from_bits(i1), f32::from_bits(i2));
|
||||
let outi = outf.to_bits();
|
||||
|
||||
if !((outf.is_nan() && f32::from_bits(expected).is_nan()) ||
|
||||
outi == expected) {{
|
||||
panic!(
|
||||
\"input: {{:?}}, output: {{}}, expected: {{}}\",
|
||||
(i1, i2),
|
||||
outi,
|
||||
expected,
|
||||
);
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
",
|
||||
stringify!($intr),
|
||||
cases)?;
|
||||
)+
|
||||
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! f32i32_f32 {
|
||||
($($intr:ident,)+) => {
|
||||
fn f32i32_f32(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
|
||||
extern "C" {
|
||||
$(fn $intr(_: f32, _: i32) -> f32;)+
|
||||
}
|
||||
|
||||
$(
|
||||
let mut cases = String::new();
|
||||
for _ in 0..NTESTS {
|
||||
let i1 = f32(rng);
|
||||
let i2 = rng.gen_range(i16::MIN, i16::MAX);
|
||||
let out = unsafe { $intr(i1, i2 as i32) };
|
||||
|
||||
let i1 = i1.to_bits();
|
||||
let out = out.to_bits();
|
||||
|
||||
write!(cases, "(({}, {}), {})", i1, i2, out).unwrap();
|
||||
cases.push(',');
|
||||
}
|
||||
|
||||
let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?;
|
||||
write!(f, "
|
||||
extern crate libm;
|
||||
|
||||
#[test]
|
||||
fn {0}() {{
|
||||
const CASES: &[((u32, i16), u32)] = &[
|
||||
{1}
|
||||
];
|
||||
|
||||
for case in CASES {{
|
||||
let ((i1, i2), expected) = *case;
|
||||
|
||||
let outf = libm::{0}(f32::from_bits(i1), i2 as i32);
|
||||
let outi = outf.to_bits();
|
||||
|
||||
if !((outf.is_nan() && f32::from_bits(expected).is_nan()) ||
|
||||
outi == expected) {{
|
||||
panic!(
|
||||
\"input: {{:?}}, output: {{}}, expected: {{}}\",
|
||||
(i1, i2),
|
||||
outi,
|
||||
expected,
|
||||
);
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
",
|
||||
stringify!($intr),
|
||||
cases)?;
|
||||
)+
|
||||
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<Error>> {
|
||||
fs::remove_dir_all("tests").ok();
|
||||
fs::create_dir("tests")?;
|
||||
|
||||
let mut rng = XorShiftRng::from_rng(&mut rand::thread_rng())?;
|
||||
|
||||
f32_f32(&mut rng)?;
|
||||
f32f32_f32(&mut rng)?;
|
||||
f32i32_f32(&mut rng)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/* Functions to test */
|
||||
|
||||
// With signature `fn(f32) -> f32`
|
||||
f32_f32! {
|
||||
fabsf,
|
||||
sqrtf,
|
||||
}
|
||||
|
||||
// With signature `fn(f32, f32) -> f32`
|
||||
f32f32_f32! {
|
||||
powf,
|
||||
}
|
||||
|
||||
// With signature `fn(f32, i32) -> f32`
|
||||
f32i32_f32! {
|
||||
scalbnf,
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user