Initial seeding from rust repo
This commit is contained in:
commit
482f0e0b74
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
/Cargo.lock
|
|
@ -0,0 +1,7 @@
|
||||||
|
install:
|
||||||
|
- curl https://static.rust-lang.org/rustup.sh | sudo sh -
|
||||||
|
script:
|
||||||
|
- cargo build --verbose
|
||||||
|
- cargo test --verbose
|
||||||
|
env:
|
||||||
|
- LD_LIBRARY_PATH=/usr/local/lib
|
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
|
||||||
|
name = "num"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = ["The Rust Project Developers"]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
|
||||||
|
name = "num"
|
||||||
|
plugin = true
|
|
@ -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.
|
|
@ -0,0 +1,25 @@
|
||||||
|
Copyright (c) 2014 The Rust Project Developers
|
||||||
|
|
||||||
|
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.
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,379 @@
|
||||||
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
|
||||||
|
//! Complex numbers.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use std::num::{Zero, One, ToStrRadix};
|
||||||
|
|
||||||
|
// FIXME #1284: handle complex NaN & infinity etc. This
|
||||||
|
// probably doesn't map to C's _Complex correctly.
|
||||||
|
|
||||||
|
/// A complex number in Cartesian form.
|
||||||
|
#[deriving(PartialEq, Clone, Hash)]
|
||||||
|
pub struct Complex<T> {
|
||||||
|
/// Real portion of the complex number
|
||||||
|
pub re: T,
|
||||||
|
/// Imaginary portion of the complex number
|
||||||
|
pub im: T
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Complex32 = Complex<f32>;
|
||||||
|
pub type Complex64 = Complex<f64>;
|
||||||
|
|
||||||
|
impl<T: Clone + Num> Complex<T> {
|
||||||
|
/// Create a new Complex
|
||||||
|
#[inline]
|
||||||
|
pub fn new(re: T, im: T) -> Complex<T> {
|
||||||
|
Complex { re: re, im: im }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the square of the norm (since `T` doesn't necessarily
|
||||||
|
/// have a sqrt function), i.e. `re^2 + im^2`.
|
||||||
|
#[inline]
|
||||||
|
pub fn norm_sqr(&self) -> T {
|
||||||
|
self.re * self.re + self.im * self.im
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Returns the complex conjugate. i.e. `re - i im`
|
||||||
|
#[inline]
|
||||||
|
pub fn conj(&self) -> Complex<T> {
|
||||||
|
Complex::new(self.re.clone(), -self.im)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Multiplies `self` by the scalar `t`.
|
||||||
|
#[inline]
|
||||||
|
pub fn scale(&self, t: T) -> Complex<T> {
|
||||||
|
Complex::new(self.re * t, self.im * t)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Divides `self` by the scalar `t`.
|
||||||
|
#[inline]
|
||||||
|
pub fn unscale(&self, t: T) -> Complex<T> {
|
||||||
|
Complex::new(self.re / t, self.im / t)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `1/self`
|
||||||
|
#[inline]
|
||||||
|
pub fn inv(&self) -> Complex<T> {
|
||||||
|
let norm_sqr = self.norm_sqr();
|
||||||
|
Complex::new(self.re / norm_sqr,
|
||||||
|
-self.im / norm_sqr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone + FloatMath> Complex<T> {
|
||||||
|
/// Calculate |self|
|
||||||
|
#[inline]
|
||||||
|
pub fn norm(&self) -> T {
|
||||||
|
self.re.hypot(self.im)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone + FloatMath> Complex<T> {
|
||||||
|
/// Calculate the principal Arg of self.
|
||||||
|
#[inline]
|
||||||
|
pub fn arg(&self) -> T {
|
||||||
|
self.im.atan2(self.re)
|
||||||
|
}
|
||||||
|
/// Convert to polar form (r, theta), such that `self = r * exp(i
|
||||||
|
/// * theta)`
|
||||||
|
#[inline]
|
||||||
|
pub fn to_polar(&self) -> (T, T) {
|
||||||
|
(self.norm(), self.arg())
|
||||||
|
}
|
||||||
|
/// Convert a polar representation into a complex number.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_polar(r: &T, theta: &T) -> Complex<T> {
|
||||||
|
Complex::new(*r * theta.cos(), *r * theta.sin())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* arithmetic */
|
||||||
|
// (a + i b) + (c + i d) == (a + c) + i (b + d)
|
||||||
|
impl<T: Clone + Num> Add<Complex<T>, Complex<T>> for Complex<T> {
|
||||||
|
#[inline]
|
||||||
|
fn add(&self, other: &Complex<T>) -> Complex<T> {
|
||||||
|
Complex::new(self.re + other.re, self.im + other.im)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// (a + i b) - (c + i d) == (a - c) + i (b - d)
|
||||||
|
impl<T: Clone + Num> Sub<Complex<T>, Complex<T>> for Complex<T> {
|
||||||
|
#[inline]
|
||||||
|
fn sub(&self, other: &Complex<T>) -> Complex<T> {
|
||||||
|
Complex::new(self.re - other.re, self.im - other.im)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// (a + i b) * (c + i d) == (a*c - b*d) + i (a*d + b*c)
|
||||||
|
impl<T: Clone + Num> Mul<Complex<T>, Complex<T>> for Complex<T> {
|
||||||
|
#[inline]
|
||||||
|
fn mul(&self, other: &Complex<T>) -> Complex<T> {
|
||||||
|
Complex::new(self.re*other.re - self.im*other.im,
|
||||||
|
self.re*other.im + self.im*other.re)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// (a + i b) / (c + i d) == [(a + i b) * (c - i d)] / (c*c + d*d)
|
||||||
|
// == [(a*c + b*d) / (c*c + d*d)] + i [(b*c - a*d) / (c*c + d*d)]
|
||||||
|
impl<T: Clone + Num> Div<Complex<T>, Complex<T>> for Complex<T> {
|
||||||
|
#[inline]
|
||||||
|
fn div(&self, other: &Complex<T>) -> Complex<T> {
|
||||||
|
let norm_sqr = other.norm_sqr();
|
||||||
|
Complex::new((self.re*other.re + self.im*other.im) / norm_sqr,
|
||||||
|
(self.im*other.re - self.re*other.im) / norm_sqr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone + Num> Neg<Complex<T>> for Complex<T> {
|
||||||
|
#[inline]
|
||||||
|
fn neg(&self) -> Complex<T> {
|
||||||
|
Complex::new(-self.re, -self.im)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* constants */
|
||||||
|
impl<T: Clone + Num> Zero for Complex<T> {
|
||||||
|
#[inline]
|
||||||
|
fn zero() -> Complex<T> {
|
||||||
|
Complex::new(Zero::zero(), Zero::zero())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_zero(&self) -> bool {
|
||||||
|
self.re.is_zero() && self.im.is_zero()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone + Num> One for Complex<T> {
|
||||||
|
#[inline]
|
||||||
|
fn one() -> Complex<T> {
|
||||||
|
Complex::new(One::one(), Zero::zero())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* string conversions */
|
||||||
|
impl<T: fmt::Show + Num + PartialOrd> fmt::Show for Complex<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
if self.im < Zero::zero() {
|
||||||
|
write!(f, "{}-{}i", self.re, -self.im)
|
||||||
|
} else {
|
||||||
|
write!(f, "{}+{}i", self.re, self.im)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ToStrRadix + Num + PartialOrd> ToStrRadix for Complex<T> {
|
||||||
|
fn to_str_radix(&self, radix: uint) -> String {
|
||||||
|
if self.im < Zero::zero() {
|
||||||
|
format!("{}-{}i",
|
||||||
|
self.re.to_str_radix(radix),
|
||||||
|
(-self.im).to_str_radix(radix))
|
||||||
|
} else {
|
||||||
|
format!("{}+{}i",
|
||||||
|
self.re.to_str_radix(radix),
|
||||||
|
self.im.to_str_radix(radix))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
#![allow(non_uppercase_statics)]
|
||||||
|
|
||||||
|
use super::{Complex64, Complex};
|
||||||
|
use std::num::{Zero, One, Float};
|
||||||
|
use std::hash::hash;
|
||||||
|
|
||||||
|
pub static _0_0i : Complex64 = Complex { re: 0.0, im: 0.0 };
|
||||||
|
pub static _1_0i : Complex64 = Complex { re: 1.0, im: 0.0 };
|
||||||
|
pub static _1_1i : Complex64 = Complex { re: 1.0, im: 1.0 };
|
||||||
|
pub static _0_1i : Complex64 = Complex { re: 0.0, im: 1.0 };
|
||||||
|
pub static _neg1_1i : Complex64 = Complex { re: -1.0, im: 1.0 };
|
||||||
|
pub static _05_05i : Complex64 = Complex { re: 0.5, im: 0.5 };
|
||||||
|
pub static all_consts : [Complex64, .. 5] = [_0_0i, _1_0i, _1_1i, _neg1_1i, _05_05i];
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_consts() {
|
||||||
|
// check our constants are what Complex::new creates
|
||||||
|
fn test(c : Complex64, r : f64, i: f64) {
|
||||||
|
assert_eq!(c, Complex::new(r,i));
|
||||||
|
}
|
||||||
|
test(_0_0i, 0.0, 0.0);
|
||||||
|
test(_1_0i, 1.0, 0.0);
|
||||||
|
test(_1_1i, 1.0, 1.0);
|
||||||
|
test(_neg1_1i, -1.0, 1.0);
|
||||||
|
test(_05_05i, 0.5, 0.5);
|
||||||
|
|
||||||
|
assert_eq!(_0_0i, Zero::zero());
|
||||||
|
assert_eq!(_1_0i, One::one());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore(cfg(target_arch = "x86"))]
|
||||||
|
// FIXME #7158: (maybe?) currently failing on x86.
|
||||||
|
fn test_norm() {
|
||||||
|
fn test(c: Complex64, ns: f64) {
|
||||||
|
assert_eq!(c.norm_sqr(), ns);
|
||||||
|
assert_eq!(c.norm(), ns.sqrt())
|
||||||
|
}
|
||||||
|
test(_0_0i, 0.0);
|
||||||
|
test(_1_0i, 1.0);
|
||||||
|
test(_1_1i, 2.0);
|
||||||
|
test(_neg1_1i, 2.0);
|
||||||
|
test(_05_05i, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_scale_unscale() {
|
||||||
|
assert_eq!(_05_05i.scale(2.0), _1_1i);
|
||||||
|
assert_eq!(_1_1i.unscale(2.0), _05_05i);
|
||||||
|
for &c in all_consts.iter() {
|
||||||
|
assert_eq!(c.scale(2.0).unscale(2.0), c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_conj() {
|
||||||
|
for &c in all_consts.iter() {
|
||||||
|
assert_eq!(c.conj(), Complex::new(c.re, -c.im));
|
||||||
|
assert_eq!(c.conj().conj(), c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_inv() {
|
||||||
|
assert_eq!(_1_1i.inv(), _05_05i.conj());
|
||||||
|
assert_eq!(_1_0i.inv(), _1_0i.inv());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_fail]
|
||||||
|
fn test_divide_by_zero_natural() {
|
||||||
|
let n = Complex::new(2i, 3i);
|
||||||
|
let d = Complex::new(0, 0);
|
||||||
|
let _x = n / d;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_fail]
|
||||||
|
#[ignore]
|
||||||
|
fn test_inv_zero() {
|
||||||
|
// FIXME #5736: should this really fail, or just NaN?
|
||||||
|
_0_0i.inv();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_arg() {
|
||||||
|
fn test(c: Complex64, arg: f64) {
|
||||||
|
assert!((c.arg() - arg).abs() < 1.0e-6)
|
||||||
|
}
|
||||||
|
test(_1_0i, 0.0);
|
||||||
|
test(_1_1i, 0.25 * Float::pi());
|
||||||
|
test(_neg1_1i, 0.75 * Float::pi());
|
||||||
|
test(_05_05i, 0.25 * Float::pi());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_polar_conv() {
|
||||||
|
fn test(c: Complex64) {
|
||||||
|
let (r, theta) = c.to_polar();
|
||||||
|
assert!((c - Complex::from_polar(&r, &theta)).norm() < 1e-6);
|
||||||
|
}
|
||||||
|
for &c in all_consts.iter() { test(c); }
|
||||||
|
}
|
||||||
|
|
||||||
|
mod arith {
|
||||||
|
use super::{_0_0i, _1_0i, _1_1i, _0_1i, _neg1_1i, _05_05i, all_consts};
|
||||||
|
use std::num::Zero;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_add() {
|
||||||
|
assert_eq!(_05_05i + _05_05i, _1_1i);
|
||||||
|
assert_eq!(_0_1i + _1_0i, _1_1i);
|
||||||
|
assert_eq!(_1_0i + _neg1_1i, _0_1i);
|
||||||
|
|
||||||
|
for &c in all_consts.iter() {
|
||||||
|
assert_eq!(_0_0i + c, c);
|
||||||
|
assert_eq!(c + _0_0i, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sub() {
|
||||||
|
assert_eq!(_05_05i - _05_05i, _0_0i);
|
||||||
|
assert_eq!(_0_1i - _1_0i, _neg1_1i);
|
||||||
|
assert_eq!(_0_1i - _neg1_1i, _1_0i);
|
||||||
|
|
||||||
|
for &c in all_consts.iter() {
|
||||||
|
assert_eq!(c - _0_0i, c);
|
||||||
|
assert_eq!(c - c, _0_0i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mul() {
|
||||||
|
assert_eq!(_05_05i * _05_05i, _0_1i.unscale(2.0));
|
||||||
|
assert_eq!(_1_1i * _0_1i, _neg1_1i);
|
||||||
|
|
||||||
|
// i^2 & i^4
|
||||||
|
assert_eq!(_0_1i * _0_1i, -_1_0i);
|
||||||
|
assert_eq!(_0_1i * _0_1i * _0_1i * _0_1i, _1_0i);
|
||||||
|
|
||||||
|
for &c in all_consts.iter() {
|
||||||
|
assert_eq!(c * _1_0i, c);
|
||||||
|
assert_eq!(_1_0i * c, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_div() {
|
||||||
|
assert_eq!(_neg1_1i / _0_1i, _1_1i);
|
||||||
|
for &c in all_consts.iter() {
|
||||||
|
if c != Zero::zero() {
|
||||||
|
assert_eq!(c / c, _1_0i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_neg() {
|
||||||
|
assert_eq!(-_1_0i + _0_1i, _neg1_1i);
|
||||||
|
assert_eq!((-_0_1i) * _0_1i, _1_0i);
|
||||||
|
for &c in all_consts.iter() {
|
||||||
|
assert_eq!(-(-c), c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_to_string() {
|
||||||
|
fn test(c : Complex64, s: String) {
|
||||||
|
assert_eq!(c.to_string(), s);
|
||||||
|
}
|
||||||
|
test(_0_0i, "0+0i".to_string());
|
||||||
|
test(_1_0i, "1+0i".to_string());
|
||||||
|
test(_0_1i, "0+1i".to_string());
|
||||||
|
test(_1_1i, "1+1i".to_string());
|
||||||
|
test(_neg1_1i, "-1+1i".to_string());
|
||||||
|
test(-_neg1_1i, "1-1i".to_string());
|
||||||
|
test(_05_05i, "0.5+0.5i".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hash() {
|
||||||
|
let a = Complex::new(0i32, 0i32);
|
||||||
|
let b = Complex::new(1i32, 0i32);
|
||||||
|
let c = Complex::new(0i32, 1i32);
|
||||||
|
assert!(hash(&a) != hash(&b));
|
||||||
|
assert!(hash(&b) != hash(&c));
|
||||||
|
assert!(hash(&c) != hash(&a));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,496 @@
|
||||||
|
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! Integer trait and functions.
|
||||||
|
|
||||||
|
pub trait Integer: Num + PartialOrd
|
||||||
|
+ Div<Self, Self>
|
||||||
|
+ Rem<Self, Self> {
|
||||||
|
/// Floored integer division.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ~~~
|
||||||
|
/// # use num::Integer;
|
||||||
|
/// assert!(( 8i).div_floor(& 3) == 2);
|
||||||
|
/// assert!(( 8i).div_floor(&-3) == -3);
|
||||||
|
/// assert!((-8i).div_floor(& 3) == -3);
|
||||||
|
/// assert!((-8i).div_floor(&-3) == 2);
|
||||||
|
///
|
||||||
|
/// assert!(( 1i).div_floor(& 2) == 0);
|
||||||
|
/// assert!(( 1i).div_floor(&-2) == -1);
|
||||||
|
/// assert!((-1i).div_floor(& 2) == -1);
|
||||||
|
/// assert!((-1i).div_floor(&-2) == 0);
|
||||||
|
/// ~~~
|
||||||
|
fn div_floor(&self, other: &Self) -> Self;
|
||||||
|
|
||||||
|
/// Floored integer modulo, satisfying:
|
||||||
|
///
|
||||||
|
/// ~~~
|
||||||
|
/// # use num::Integer;
|
||||||
|
/// # let n = 1i; let d = 1i;
|
||||||
|
/// assert!(n.div_floor(&d) * d + n.mod_floor(&d) == n)
|
||||||
|
/// ~~~
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ~~~
|
||||||
|
/// # use num::Integer;
|
||||||
|
/// assert!(( 8i).mod_floor(& 3) == 2);
|
||||||
|
/// assert!(( 8i).mod_floor(&-3) == -1);
|
||||||
|
/// assert!((-8i).mod_floor(& 3) == 1);
|
||||||
|
/// assert!((-8i).mod_floor(&-3) == -2);
|
||||||
|
///
|
||||||
|
/// assert!(( 1i).mod_floor(& 2) == 1);
|
||||||
|
/// assert!(( 1i).mod_floor(&-2) == -1);
|
||||||
|
/// assert!((-1i).mod_floor(& 2) == 1);
|
||||||
|
/// assert!((-1i).mod_floor(&-2) == -1);
|
||||||
|
/// ~~~
|
||||||
|
fn mod_floor(&self, other: &Self) -> Self;
|
||||||
|
|
||||||
|
/// Greatest Common Divisor (GCD).
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ~~~
|
||||||
|
/// # use num::Integer;
|
||||||
|
/// assert_eq!(6i.gcd(&8), 2);
|
||||||
|
/// assert_eq!(7i.gcd(&3), 1);
|
||||||
|
/// ~~~
|
||||||
|
fn gcd(&self, other: &Self) -> Self;
|
||||||
|
|
||||||
|
/// Lowest Common Multiple (LCM).
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ~~~
|
||||||
|
/// # use num::Integer;
|
||||||
|
/// assert_eq!(7i.lcm(&3), 21);
|
||||||
|
/// assert_eq!(2i.lcm(&4), 4);
|
||||||
|
/// ~~~
|
||||||
|
fn lcm(&self, other: &Self) -> Self;
|
||||||
|
|
||||||
|
/// Deprecated, use `is_multiple_of` instead.
|
||||||
|
#[deprecated = "function renamed to `is_multiple_of`"]
|
||||||
|
fn divides(&self, other: &Self) -> bool;
|
||||||
|
|
||||||
|
/// Returns `true` if `other` is a multiple of `self`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ~~~
|
||||||
|
/// # use num::Integer;
|
||||||
|
/// assert_eq!(9i.is_multiple_of(&3), true);
|
||||||
|
/// assert_eq!(3i.is_multiple_of(&9), false);
|
||||||
|
/// ~~~
|
||||||
|
fn is_multiple_of(&self, other: &Self) -> bool;
|
||||||
|
|
||||||
|
/// Returns `true` if the number is even.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ~~~
|
||||||
|
/// # use num::Integer;
|
||||||
|
/// assert_eq!(3i.is_even(), false);
|
||||||
|
/// assert_eq!(4i.is_even(), true);
|
||||||
|
/// ~~~
|
||||||
|
fn is_even(&self) -> bool;
|
||||||
|
|
||||||
|
/// Returns `true` if the number is odd.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ~~~
|
||||||
|
/// # use num::Integer;
|
||||||
|
/// assert_eq!(3i.is_odd(), true);
|
||||||
|
/// assert_eq!(4i.is_odd(), false);
|
||||||
|
/// ~~~
|
||||||
|
fn is_odd(&self) -> bool;
|
||||||
|
|
||||||
|
/// Simultaneous truncated integer division and modulus.
|
||||||
|
/// Returns `(quotient, remainder)`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ~~~
|
||||||
|
/// # use num::Integer;
|
||||||
|
/// assert_eq!(( 8i).div_rem( &3), ( 2, 2));
|
||||||
|
/// assert_eq!(( 8i).div_rem(&-3), (-2, 2));
|
||||||
|
/// assert_eq!((-8i).div_rem( &3), (-2, -2));
|
||||||
|
/// assert_eq!((-8i).div_rem(&-3), ( 2, -2));
|
||||||
|
///
|
||||||
|
/// assert_eq!(( 1i).div_rem( &2), ( 0, 1));
|
||||||
|
/// assert_eq!(( 1i).div_rem(&-2), ( 0, 1));
|
||||||
|
/// assert_eq!((-1i).div_rem( &2), ( 0, -1));
|
||||||
|
/// assert_eq!((-1i).div_rem(&-2), ( 0, -1));
|
||||||
|
/// ~~~
|
||||||
|
#[inline]
|
||||||
|
fn div_rem(&self, other: &Self) -> (Self, Self) {
|
||||||
|
(*self / *other, *self % *other)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Simultaneous floored integer division and modulus.
|
||||||
|
/// Returns `(quotient, remainder)`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ~~~
|
||||||
|
/// # use num::Integer;
|
||||||
|
/// assert_eq!(( 8i).div_mod_floor( &3), ( 2, 2));
|
||||||
|
/// assert_eq!(( 8i).div_mod_floor(&-3), (-3, -1));
|
||||||
|
/// assert_eq!((-8i).div_mod_floor( &3), (-3, 1));
|
||||||
|
/// assert_eq!((-8i).div_mod_floor(&-3), ( 2, -2));
|
||||||
|
///
|
||||||
|
/// assert_eq!(( 1i).div_mod_floor( &2), ( 0, 1));
|
||||||
|
/// assert_eq!(( 1i).div_mod_floor(&-2), (-1, -1));
|
||||||
|
/// assert_eq!((-1i).div_mod_floor( &2), (-1, 1));
|
||||||
|
/// assert_eq!((-1i).div_mod_floor(&-2), ( 0, -1));
|
||||||
|
/// ~~~
|
||||||
|
fn div_mod_floor(&self, other: &Self) -> (Self, Self) {
|
||||||
|
(self.div_floor(other), self.mod_floor(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Simultaneous integer division and modulus
|
||||||
|
#[inline] pub fn div_rem<T: Integer>(x: T, y: T) -> (T, T) { x.div_rem(&y) }
|
||||||
|
/// Floored integer division
|
||||||
|
#[inline] pub fn div_floor<T: Integer>(x: T, y: T) -> T { x.div_floor(&y) }
|
||||||
|
/// Floored integer modulus
|
||||||
|
#[inline] pub fn mod_floor<T: Integer>(x: T, y: T) -> T { x.mod_floor(&y) }
|
||||||
|
/// Simultaneous floored integer division and modulus
|
||||||
|
#[inline] pub fn div_mod_floor<T: Integer>(x: T, y: T) -> (T, T) { x.div_mod_floor(&y) }
|
||||||
|
|
||||||
|
/// Calculates the Greatest Common Divisor (GCD) of the number and `other`. The
|
||||||
|
/// result is always positive.
|
||||||
|
#[inline(always)] pub fn gcd<T: Integer>(x: T, y: T) -> T { x.gcd(&y) }
|
||||||
|
/// Calculates the Lowest Common Multiple (LCM) of the number and `other`.
|
||||||
|
#[inline(always)] pub fn lcm<T: Integer>(x: T, y: T) -> T { x.lcm(&y) }
|
||||||
|
|
||||||
|
macro_rules! impl_integer_for_int {
|
||||||
|
($T:ty, $test_mod:ident) => (
|
||||||
|
impl Integer for $T {
|
||||||
|
/// Floored integer division
|
||||||
|
#[inline]
|
||||||
|
fn div_floor(&self, other: &$T) -> $T {
|
||||||
|
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
|
||||||
|
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
|
||||||
|
match self.div_rem(other) {
|
||||||
|
(d, r) if (r > 0 && *other < 0)
|
||||||
|
|| (r < 0 && *other > 0) => d - 1,
|
||||||
|
(d, _) => d,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Floored integer modulo
|
||||||
|
#[inline]
|
||||||
|
fn mod_floor(&self, other: &$T) -> $T {
|
||||||
|
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
|
||||||
|
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
|
||||||
|
match *self % *other {
|
||||||
|
r if (r > 0 && *other < 0)
|
||||||
|
|| (r < 0 && *other > 0) => r + *other,
|
||||||
|
r => r,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculates `div_floor` and `mod_floor` simultaneously
|
||||||
|
#[inline]
|
||||||
|
fn div_mod_floor(&self, other: &$T) -> ($T,$T) {
|
||||||
|
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
|
||||||
|
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
|
||||||
|
match self.div_rem(other) {
|
||||||
|
(d, r) if (r > 0 && *other < 0)
|
||||||
|
|| (r < 0 && *other > 0) => (d - 1, r + *other),
|
||||||
|
(d, r) => (d, r),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculates the Greatest Common Divisor (GCD) of the number and
|
||||||
|
/// `other`. The result is always positive.
|
||||||
|
#[inline]
|
||||||
|
fn gcd(&self, other: &$T) -> $T {
|
||||||
|
// Use Euclid's algorithm
|
||||||
|
let mut m = *self;
|
||||||
|
let mut n = *other;
|
||||||
|
while m != 0 {
|
||||||
|
let temp = m;
|
||||||
|
m = n % temp;
|
||||||
|
n = temp;
|
||||||
|
}
|
||||||
|
n.abs()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculates the Lowest Common Multiple (LCM) of the number and
|
||||||
|
/// `other`.
|
||||||
|
#[inline]
|
||||||
|
fn lcm(&self, other: &$T) -> $T {
|
||||||
|
// should not have to recalculate abs
|
||||||
|
((*self * *other) / self.gcd(other)).abs()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deprecated, use `is_multiple_of` instead.
|
||||||
|
#[deprecated = "function renamed to `is_multiple_of`"]
|
||||||
|
#[inline]
|
||||||
|
fn divides(&self, other: &$T) -> bool { return self.is_multiple_of(other); }
|
||||||
|
|
||||||
|
/// Returns `true` if the number is a multiple of `other`.
|
||||||
|
#[inline]
|
||||||
|
fn is_multiple_of(&self, other: &$T) -> bool { *self % *other == 0 }
|
||||||
|
|
||||||
|
/// Returns `true` if the number is divisible by `2`
|
||||||
|
#[inline]
|
||||||
|
fn is_even(&self) -> bool { self & 1 == 0 }
|
||||||
|
|
||||||
|
/// Returns `true` if the number is not divisible by `2`
|
||||||
|
#[inline]
|
||||||
|
fn is_odd(&self) -> bool { !self.is_even() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod $test_mod {
|
||||||
|
use Integer;
|
||||||
|
|
||||||
|
/// Checks that the division rule holds for:
|
||||||
|
///
|
||||||
|
/// - `n`: numerator (dividend)
|
||||||
|
/// - `d`: denominator (divisor)
|
||||||
|
/// - `qr`: quotient and remainder
|
||||||
|
#[cfg(test)]
|
||||||
|
fn test_division_rule((n,d): ($T,$T), (q,r): ($T,$T)) {
|
||||||
|
assert_eq!(d * q + r, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_div_rem() {
|
||||||
|
fn test_nd_dr(nd: ($T,$T), qr: ($T,$T)) {
|
||||||
|
let (n,d) = nd;
|
||||||
|
let separate_div_rem = (n / d, n % d);
|
||||||
|
let combined_div_rem = n.div_rem(&d);
|
||||||
|
|
||||||
|
assert_eq!(separate_div_rem, qr);
|
||||||
|
assert_eq!(combined_div_rem, qr);
|
||||||
|
|
||||||
|
test_division_rule(nd, separate_div_rem);
|
||||||
|
test_division_rule(nd, combined_div_rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
test_nd_dr(( 8, 3), ( 2, 2));
|
||||||
|
test_nd_dr(( 8, -3), (-2, 2));
|
||||||
|
test_nd_dr((-8, 3), (-2, -2));
|
||||||
|
test_nd_dr((-8, -3), ( 2, -2));
|
||||||
|
|
||||||
|
test_nd_dr(( 1, 2), ( 0, 1));
|
||||||
|
test_nd_dr(( 1, -2), ( 0, 1));
|
||||||
|
test_nd_dr((-1, 2), ( 0, -1));
|
||||||
|
test_nd_dr((-1, -2), ( 0, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_div_mod_floor() {
|
||||||
|
fn test_nd_dm(nd: ($T,$T), dm: ($T,$T)) {
|
||||||
|
let (n,d) = nd;
|
||||||
|
let separate_div_mod_floor = (n.div_floor(&d), n.mod_floor(&d));
|
||||||
|
let combined_div_mod_floor = n.div_mod_floor(&d);
|
||||||
|
|
||||||
|
assert_eq!(separate_div_mod_floor, dm);
|
||||||
|
assert_eq!(combined_div_mod_floor, dm);
|
||||||
|
|
||||||
|
test_division_rule(nd, separate_div_mod_floor);
|
||||||
|
test_division_rule(nd, combined_div_mod_floor);
|
||||||
|
}
|
||||||
|
|
||||||
|
test_nd_dm(( 8, 3), ( 2, 2));
|
||||||
|
test_nd_dm(( 8, -3), (-3, -1));
|
||||||
|
test_nd_dm((-8, 3), (-3, 1));
|
||||||
|
test_nd_dm((-8, -3), ( 2, -2));
|
||||||
|
|
||||||
|
test_nd_dm(( 1, 2), ( 0, 1));
|
||||||
|
test_nd_dm(( 1, -2), (-1, -1));
|
||||||
|
test_nd_dm((-1, 2), (-1, 1));
|
||||||
|
test_nd_dm((-1, -2), ( 0, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_gcd() {
|
||||||
|
assert_eq!((10 as $T).gcd(&2), 2 as $T);
|
||||||
|
assert_eq!((10 as $T).gcd(&3), 1 as $T);
|
||||||
|
assert_eq!((0 as $T).gcd(&3), 3 as $T);
|
||||||
|
assert_eq!((3 as $T).gcd(&3), 3 as $T);
|
||||||
|
assert_eq!((56 as $T).gcd(&42), 14 as $T);
|
||||||
|
assert_eq!((3 as $T).gcd(&-3), 3 as $T);
|
||||||
|
assert_eq!((-6 as $T).gcd(&3), 3 as $T);
|
||||||
|
assert_eq!((-4 as $T).gcd(&-2), 2 as $T);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lcm() {
|
||||||
|
assert_eq!((1 as $T).lcm(&0), 0 as $T);
|
||||||
|
assert_eq!((0 as $T).lcm(&1), 0 as $T);
|
||||||
|
assert_eq!((1 as $T).lcm(&1), 1 as $T);
|
||||||
|
assert_eq!((-1 as $T).lcm(&1), 1 as $T);
|
||||||
|
assert_eq!((1 as $T).lcm(&-1), 1 as $T);
|
||||||
|
assert_eq!((-1 as $T).lcm(&-1), 1 as $T);
|
||||||
|
assert_eq!((8 as $T).lcm(&9), 72 as $T);
|
||||||
|
assert_eq!((11 as $T).lcm(&5), 55 as $T);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_even() {
|
||||||
|
assert_eq!((-4 as $T).is_even(), true);
|
||||||
|
assert_eq!((-3 as $T).is_even(), false);
|
||||||
|
assert_eq!((-2 as $T).is_even(), true);
|
||||||
|
assert_eq!((-1 as $T).is_even(), false);
|
||||||
|
assert_eq!((0 as $T).is_even(), true);
|
||||||
|
assert_eq!((1 as $T).is_even(), false);
|
||||||
|
assert_eq!((2 as $T).is_even(), true);
|
||||||
|
assert_eq!((3 as $T).is_even(), false);
|
||||||
|
assert_eq!((4 as $T).is_even(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_odd() {
|
||||||
|
assert_eq!((-4 as $T).is_odd(), false);
|
||||||
|
assert_eq!((-3 as $T).is_odd(), true);
|
||||||
|
assert_eq!((-2 as $T).is_odd(), false);
|
||||||
|
assert_eq!((-1 as $T).is_odd(), true);
|
||||||
|
assert_eq!((0 as $T).is_odd(), false);
|
||||||
|
assert_eq!((1 as $T).is_odd(), true);
|
||||||
|
assert_eq!((2 as $T).is_odd(), false);
|
||||||
|
assert_eq!((3 as $T).is_odd(), true);
|
||||||
|
assert_eq!((4 as $T).is_odd(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_integer_for_int!(i8, test_integer_i8)
|
||||||
|
impl_integer_for_int!(i16, test_integer_i16)
|
||||||
|
impl_integer_for_int!(i32, test_integer_i32)
|
||||||
|
impl_integer_for_int!(i64, test_integer_i64)
|
||||||
|
impl_integer_for_int!(int, test_integer_int)
|
||||||
|
|
||||||
|
macro_rules! impl_integer_for_uint {
|
||||||
|
($T:ty, $test_mod:ident) => (
|
||||||
|
impl Integer for $T {
|
||||||
|
/// Unsigned integer division. Returns the same result as `div` (`/`).
|
||||||
|
#[inline]
|
||||||
|
fn div_floor(&self, other: &$T) -> $T { *self / *other }
|
||||||
|
|
||||||
|
/// Unsigned integer modulo operation. Returns the same result as `rem` (`%`).
|
||||||
|
#[inline]
|
||||||
|
fn mod_floor(&self, other: &$T) -> $T { *self % *other }
|
||||||
|
|
||||||
|
/// Calculates the Greatest Common Divisor (GCD) of the number and `other`
|
||||||
|
#[inline]
|
||||||
|
fn gcd(&self, other: &$T) -> $T {
|
||||||
|
// Use Euclid's algorithm
|
||||||
|
let mut m = *self;
|
||||||
|
let mut n = *other;
|
||||||
|
while m != 0 {
|
||||||
|
let temp = m;
|
||||||
|
m = n % temp;
|
||||||
|
n = temp;
|
||||||
|
}
|
||||||
|
n
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculates the Lowest Common Multiple (LCM) of the number and `other`.
|
||||||
|
#[inline]
|
||||||
|
fn lcm(&self, other: &$T) -> $T {
|
||||||
|
(*self * *other) / self.gcd(other)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deprecated, use `is_multiple_of` instead.
|
||||||
|
#[deprecated = "function renamed to `is_multiple_of`"]
|
||||||
|
#[inline]
|
||||||
|
fn divides(&self, other: &$T) -> bool { return self.is_multiple_of(other); }
|
||||||
|
|
||||||
|
/// Returns `true` if the number is a multiple of `other`.
|
||||||
|
#[inline]
|
||||||
|
fn is_multiple_of(&self, other: &$T) -> bool { *self % *other == 0 }
|
||||||
|
|
||||||
|
/// Returns `true` if the number is divisible by `2`.
|
||||||
|
#[inline]
|
||||||
|
fn is_even(&self) -> bool { self & 1 == 0 }
|
||||||
|
|
||||||
|
/// Returns `true` if the number is not divisible by `2`.
|
||||||
|
#[inline]
|
||||||
|
fn is_odd(&self) -> bool { !self.is_even() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod $test_mod {
|
||||||
|
use Integer;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_div_mod_floor() {
|
||||||
|
assert_eq!((10 as $T).div_floor(&(3 as $T)), 3 as $T);
|
||||||
|
assert_eq!((10 as $T).mod_floor(&(3 as $T)), 1 as $T);
|
||||||
|
assert_eq!((10 as $T).div_mod_floor(&(3 as $T)), (3 as $T, 1 as $T));
|
||||||
|
assert_eq!((5 as $T).div_floor(&(5 as $T)), 1 as $T);
|
||||||
|
assert_eq!((5 as $T).mod_floor(&(5 as $T)), 0 as $T);
|
||||||
|
assert_eq!((5 as $T).div_mod_floor(&(5 as $T)), (1 as $T, 0 as $T));
|
||||||
|
assert_eq!((3 as $T).div_floor(&(7 as $T)), 0 as $T);
|
||||||
|
assert_eq!((3 as $T).mod_floor(&(7 as $T)), 3 as $T);
|
||||||
|
assert_eq!((3 as $T).div_mod_floor(&(7 as $T)), (0 as $T, 3 as $T));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_gcd() {
|
||||||
|
assert_eq!((10 as $T).gcd(&2), 2 as $T);
|
||||||
|
assert_eq!((10 as $T).gcd(&3), 1 as $T);
|
||||||
|
assert_eq!((0 as $T).gcd(&3), 3 as $T);
|
||||||
|
assert_eq!((3 as $T).gcd(&3), 3 as $T);
|
||||||
|
assert_eq!((56 as $T).gcd(&42), 14 as $T);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lcm() {
|
||||||
|
assert_eq!((1 as $T).lcm(&0), 0 as $T);
|
||||||
|
assert_eq!((0 as $T).lcm(&1), 0 as $T);
|
||||||
|
assert_eq!((1 as $T).lcm(&1), 1 as $T);
|
||||||
|
assert_eq!((8 as $T).lcm(&9), 72 as $T);
|
||||||
|
assert_eq!((11 as $T).lcm(&5), 55 as $T);
|
||||||
|
assert_eq!((99 as $T).lcm(&17), 1683 as $T);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_is_multiple_of() {
|
||||||
|
assert!((6 as $T).is_multiple_of(&(6 as $T)));
|
||||||
|
assert!((6 as $T).is_multiple_of(&(3 as $T)));
|
||||||
|
assert!((6 as $T).is_multiple_of(&(1 as $T)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_even() {
|
||||||
|
assert_eq!((0 as $T).is_even(), true);
|
||||||
|
assert_eq!((1 as $T).is_even(), false);
|
||||||
|
assert_eq!((2 as $T).is_even(), true);
|
||||||
|
assert_eq!((3 as $T).is_even(), false);
|
||||||
|
assert_eq!((4 as $T).is_even(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_odd() {
|
||||||
|
assert_eq!((0 as $T).is_odd(), false);
|
||||||
|
assert_eq!((1 as $T).is_odd(), true);
|
||||||
|
assert_eq!((2 as $T).is_odd(), false);
|
||||||
|
assert_eq!((3 as $T).is_odd(), true);
|
||||||
|
assert_eq!((4 as $T).is_odd(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_integer_for_uint!(u8, test_integer_u8)
|
||||||
|
impl_integer_for_uint!(u16, test_integer_u16)
|
||||||
|
impl_integer_for_uint!(u32, test_integer_u32)
|
||||||
|
impl_integer_for_uint!(u64, test_integer_u64)
|
||||||
|
impl_integer_for_uint!(uint, test_integer_uint)
|
|
@ -0,0 +1,69 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! Simple numerics.
|
||||||
|
//!
|
||||||
|
//! This crate contains arbitrary-sized integer, rational, and complex types.
|
||||||
|
//!
|
||||||
|
//! ## Example
|
||||||
|
//!
|
||||||
|
//! This example uses the BigRational type and [Newton's method][newt] to
|
||||||
|
//! approximate a square root to arbitrary precision:
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! extern crate num;
|
||||||
|
//!
|
||||||
|
//! use num::bigint::BigInt;
|
||||||
|
//! use num::rational::{Ratio, BigRational};
|
||||||
|
//!
|
||||||
|
//! fn approx_sqrt(number: u64, iterations: uint) -> BigRational {
|
||||||
|
//! let start: Ratio<BigInt> = Ratio::from_integer(FromPrimitive::from_u64(number).unwrap());
|
||||||
|
//! let mut approx = start.clone();
|
||||||
|
//!
|
||||||
|
//! for _ in range(0, iterations) {
|
||||||
|
//! approx = (approx + (start / approx)) /
|
||||||
|
//! Ratio::from_integer(FromPrimitive::from_u64(2).unwrap());
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! approx
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! fn main() {
|
||||||
|
//! println!("{}", approx_sqrt(10, 4)); // prints 4057691201/1283082416
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! [newt]: https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method
|
||||||
|
|
||||||
|
#![feature(macro_rules)]
|
||||||
|
#![feature(default_type_params)]
|
||||||
|
|
||||||
|
#![crate_name = "num"]
|
||||||
|
#![experimental]
|
||||||
|
#![crate_type = "rlib"]
|
||||||
|
#![crate_type = "dylib"]
|
||||||
|
#![license = "MIT/ASL2"]
|
||||||
|
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||||
|
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||||
|
html_root_url = "http://doc.rust-lang.org/master/",
|
||||||
|
html_playground_url = "http://play.rust-lang.org/")]
|
||||||
|
#![allow(deprecated)] // from_str_radix
|
||||||
|
|
||||||
|
extern crate rand;
|
||||||
|
|
||||||
|
pub use bigint::{BigInt, BigUint};
|
||||||
|
pub use rational::{Rational, BigRational};
|
||||||
|
pub use complex::Complex;
|
||||||
|
pub use integer::Integer;
|
||||||
|
|
||||||
|
pub mod bigint;
|
||||||
|
pub mod complex;
|
||||||
|
pub mod integer;
|
||||||
|
pub mod rational;
|
|
@ -0,0 +1,761 @@
|
||||||
|
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! Rational numbers
|
||||||
|
|
||||||
|
use Integer;
|
||||||
|
|
||||||
|
use std::cmp;
|
||||||
|
use std::fmt;
|
||||||
|
use std::from_str::FromStr;
|
||||||
|
use std::num;
|
||||||
|
use std::num::{Zero, One, ToStrRadix, FromStrRadix};
|
||||||
|
|
||||||
|
use bigint::{BigInt, BigUint, Sign, Plus, Minus};
|
||||||
|
|
||||||
|
/// Represents the ratio between 2 numbers.
|
||||||
|
#[deriving(Clone, Hash)]
|
||||||
|
#[allow(missing_doc)]
|
||||||
|
pub struct Ratio<T> {
|
||||||
|
numer: T,
|
||||||
|
denom: T
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Alias for a `Ratio` of machine-sized integers.
|
||||||
|
pub type Rational = Ratio<int>;
|
||||||
|
pub type Rational32 = Ratio<i32>;
|
||||||
|
pub type Rational64 = Ratio<i64>;
|
||||||
|
|
||||||
|
/// Alias for arbitrary precision rationals.
|
||||||
|
pub type BigRational = Ratio<BigInt>;
|
||||||
|
|
||||||
|
impl<T: Clone + Integer + PartialOrd>
|
||||||
|
Ratio<T> {
|
||||||
|
/// Creates a ratio representing the integer `t`.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_integer(t: T) -> Ratio<T> {
|
||||||
|
Ratio::new_raw(t, One::one())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a ratio without checking for `denom == 0` or reducing.
|
||||||
|
#[inline]
|
||||||
|
pub fn new_raw(numer: T, denom: T) -> Ratio<T> {
|
||||||
|
Ratio { numer: numer, denom: denom }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new Ratio. Fails if `denom == 0`.
|
||||||
|
#[inline]
|
||||||
|
pub fn new(numer: T, denom: T) -> Ratio<T> {
|
||||||
|
if denom == Zero::zero() {
|
||||||
|
fail!("denominator == 0");
|
||||||
|
}
|
||||||
|
let mut ret = Ratio::new_raw(numer, denom);
|
||||||
|
ret.reduce();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts to an integer.
|
||||||
|
#[inline]
|
||||||
|
pub fn to_integer(&self) -> T {
|
||||||
|
self.trunc().numer
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets an immutable reference to the numerator.
|
||||||
|
#[inline]
|
||||||
|
pub fn numer<'a>(&'a self) -> &'a T {
|
||||||
|
&self.numer
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets an immutable reference to the denominator.
|
||||||
|
#[inline]
|
||||||
|
pub fn denom<'a>(&'a self) -> &'a T {
|
||||||
|
&self.denom
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the rational number is an integer (denominator is 1).
|
||||||
|
#[inline]
|
||||||
|
pub fn is_integer(&self) -> bool {
|
||||||
|
self.denom == One::one()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Put self into lowest terms, with denom > 0.
|
||||||
|
fn reduce(&mut self) {
|
||||||
|
let g : T = self.numer.gcd(&self.denom);
|
||||||
|
|
||||||
|
// FIXME(#5992): assignment operator overloads
|
||||||
|
// self.numer /= g;
|
||||||
|
self.numer = self.numer / g;
|
||||||
|
// FIXME(#5992): assignment operator overloads
|
||||||
|
// self.denom /= g;
|
||||||
|
self.denom = self.denom / g;
|
||||||
|
|
||||||
|
// keep denom positive!
|
||||||
|
if self.denom < Zero::zero() {
|
||||||
|
self.numer = -self.numer;
|
||||||
|
self.denom = -self.denom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a `reduce`d copy of self.
|
||||||
|
pub fn reduced(&self) -> Ratio<T> {
|
||||||
|
let mut ret = self.clone();
|
||||||
|
ret.reduce();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the reciprocal.
|
||||||
|
#[inline]
|
||||||
|
pub fn recip(&self) -> Ratio<T> {
|
||||||
|
Ratio::new_raw(self.denom.clone(), self.numer.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rounds towards minus infinity.
|
||||||
|
#[inline]
|
||||||
|
pub fn floor(&self) -> Ratio<T> {
|
||||||
|
if *self < Zero::zero() {
|
||||||
|
Ratio::from_integer((self.numer - self.denom + One::one()) / self.denom)
|
||||||
|
} else {
|
||||||
|
Ratio::from_integer(self.numer / self.denom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rounds towards plus infinity.
|
||||||
|
#[inline]
|
||||||
|
pub fn ceil(&self) -> Ratio<T> {
|
||||||
|
if *self < Zero::zero() {
|
||||||
|
Ratio::from_integer(self.numer / self.denom)
|
||||||
|
} else {
|
||||||
|
Ratio::from_integer((self.numer + self.denom - One::one()) / self.denom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rounds to the nearest integer. Rounds half-way cases away from zero.
|
||||||
|
#[inline]
|
||||||
|
pub fn round(&self) -> Ratio<T> {
|
||||||
|
if *self < Zero::zero() {
|
||||||
|
// a/b - 1/2 = (2*a - b)/(2*b)
|
||||||
|
Ratio::from_integer((self.numer + self.numer - self.denom) / (self.denom + self.denom))
|
||||||
|
} else {
|
||||||
|
// a/b + 1/2 = (2*a + b)/(2*b)
|
||||||
|
Ratio::from_integer((self.numer + self.numer + self.denom) / (self.denom + self.denom))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rounds towards zero.
|
||||||
|
#[inline]
|
||||||
|
pub fn trunc(&self) -> Ratio<T> {
|
||||||
|
Ratio::from_integer(self.numer / self.denom)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the fractional part of a number.
|
||||||
|
#[inline]
|
||||||
|
pub fn fract(&self) -> Ratio<T> {
|
||||||
|
Ratio::new_raw(self.numer % self.denom, self.denom.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ratio<BigInt> {
|
||||||
|
/// Converts a float into a rational number.
|
||||||
|
pub fn from_float<T: Float>(f: T) -> Option<BigRational> {
|
||||||
|
if !f.is_finite() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let (mantissa, exponent, sign) = f.integer_decode();
|
||||||
|
let bigint_sign: Sign = if sign == 1 { Plus } else { Minus };
|
||||||
|
if exponent < 0 {
|
||||||
|
let one: BigInt = One::one();
|
||||||
|
let denom: BigInt = one << ((-exponent) as uint);
|
||||||
|
let numer: BigUint = FromPrimitive::from_u64(mantissa).unwrap();
|
||||||
|
Some(Ratio::new(BigInt::from_biguint(bigint_sign, numer), denom))
|
||||||
|
} else {
|
||||||
|
let mut numer: BigUint = FromPrimitive::from_u64(mantissa).unwrap();
|
||||||
|
numer = numer << (exponent as uint);
|
||||||
|
Some(Ratio::from_integer(BigInt::from_biguint(bigint_sign, numer)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Comparisons */
|
||||||
|
|
||||||
|
// comparing a/b and c/d is the same as comparing a*d and b*c, so we
|
||||||
|
// abstract that pattern. The following macro takes a trait and either
|
||||||
|
// a comma-separated list of "method name -> return value" or just
|
||||||
|
// "method name" (return value is bool in that case)
|
||||||
|
macro_rules! cmp_impl {
|
||||||
|
(impl $imp:ident, $($method:ident),+) => {
|
||||||
|
cmp_impl!(impl $imp, $($method -> bool),+)
|
||||||
|
};
|
||||||
|
// return something other than a Ratio<T>
|
||||||
|
(impl $imp:ident, $($method:ident -> $res:ty),*) => {
|
||||||
|
impl<T: Mul<T,T> + $imp> $imp for Ratio<T> {
|
||||||
|
$(
|
||||||
|
#[inline]
|
||||||
|
fn $method(&self, other: &Ratio<T>) -> $res {
|
||||||
|
(self.numer * other.denom). $method (&(self.denom*other.numer))
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
cmp_impl!(impl PartialEq, eq, ne)
|
||||||
|
cmp_impl!(impl PartialOrd, lt -> bool, gt -> bool, le -> bool, ge -> bool,
|
||||||
|
partial_cmp -> Option<cmp::Ordering>)
|
||||||
|
cmp_impl!(impl Eq, )
|
||||||
|
cmp_impl!(impl Ord, cmp -> cmp::Ordering)
|
||||||
|
|
||||||
|
/* Arithmetic */
|
||||||
|
// a/b * c/d = (a*c)/(b*d)
|
||||||
|
impl<T: Clone + Integer + PartialOrd>
|
||||||
|
Mul<Ratio<T>,Ratio<T>> for Ratio<T> {
|
||||||
|
#[inline]
|
||||||
|
fn mul(&self, rhs: &Ratio<T>) -> Ratio<T> {
|
||||||
|
Ratio::new(self.numer * rhs.numer, self.denom * rhs.denom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// (a/b) / (c/d) = (a*d)/(b*c)
|
||||||
|
impl<T: Clone + Integer + PartialOrd>
|
||||||
|
Div<Ratio<T>,Ratio<T>> for Ratio<T> {
|
||||||
|
#[inline]
|
||||||
|
fn div(&self, rhs: &Ratio<T>) -> Ratio<T> {
|
||||||
|
Ratio::new(self.numer * rhs.denom, self.denom * rhs.numer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abstracts the a/b `op` c/d = (a*d `op` b*d) / (b*d) pattern
|
||||||
|
macro_rules! arith_impl {
|
||||||
|
(impl $imp:ident, $method:ident) => {
|
||||||
|
impl<T: Clone + Integer + PartialOrd>
|
||||||
|
$imp<Ratio<T>,Ratio<T>> for Ratio<T> {
|
||||||
|
#[inline]
|
||||||
|
fn $method(&self, rhs: &Ratio<T>) -> Ratio<T> {
|
||||||
|
Ratio::new((self.numer * rhs.denom).$method(&(self.denom * rhs.numer)),
|
||||||
|
self.denom * rhs.denom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// a/b + c/d = (a*d + b*c)/(b*d)
|
||||||
|
arith_impl!(impl Add, add)
|
||||||
|
|
||||||
|
// a/b - c/d = (a*d - b*c)/(b*d)
|
||||||
|
arith_impl!(impl Sub, sub)
|
||||||
|
|
||||||
|
// a/b % c/d = (a*d % b*c)/(b*d)
|
||||||
|
arith_impl!(impl Rem, rem)
|
||||||
|
|
||||||
|
impl<T: Clone + Integer + PartialOrd>
|
||||||
|
Neg<Ratio<T>> for Ratio<T> {
|
||||||
|
#[inline]
|
||||||
|
fn neg(&self) -> Ratio<T> {
|
||||||
|
Ratio::new_raw(-self.numer, self.denom.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Constants */
|
||||||
|
impl<T: Clone + Integer + PartialOrd>
|
||||||
|
Zero for Ratio<T> {
|
||||||
|
#[inline]
|
||||||
|
fn zero() -> Ratio<T> {
|
||||||
|
Ratio::new_raw(Zero::zero(), One::one())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_zero(&self) -> bool {
|
||||||
|
*self == Zero::zero()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone + Integer + PartialOrd>
|
||||||
|
One for Ratio<T> {
|
||||||
|
#[inline]
|
||||||
|
fn one() -> Ratio<T> {
|
||||||
|
Ratio::new_raw(One::one(), One::one())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone + Integer + PartialOrd>
|
||||||
|
Num for Ratio<T> {}
|
||||||
|
|
||||||
|
impl<T: Clone + Integer + PartialOrd>
|
||||||
|
num::Signed for Ratio<T> {
|
||||||
|
#[inline]
|
||||||
|
fn abs(&self) -> Ratio<T> {
|
||||||
|
if self.is_negative() { -self.clone() } else { self.clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn abs_sub(&self, other: &Ratio<T>) -> Ratio<T> {
|
||||||
|
if *self <= *other { Zero::zero() } else { *self - *other }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn signum(&self) -> Ratio<T> {
|
||||||
|
if *self > Zero::zero() {
|
||||||
|
num::one()
|
||||||
|
} else if self.is_zero() {
|
||||||
|
num::zero()
|
||||||
|
} else {
|
||||||
|
- num::one::<Ratio<T>>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_positive(&self) -> bool { *self > Zero::zero() }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_negative(&self) -> bool { *self < Zero::zero() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* String conversions */
|
||||||
|
impl<T: fmt::Show + Eq + One> fmt::Show for Ratio<T> {
|
||||||
|
/// Renders as `numer/denom`. If denom=1, renders as numer.
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
if self.denom == One::one() {
|
||||||
|
write!(f, "{}", self.numer)
|
||||||
|
} else {
|
||||||
|
write!(f, "{}/{}", self.numer, self.denom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ToStrRadix> ToStrRadix for Ratio<T> {
|
||||||
|
/// Renders as `numer/denom` where the numbers are in base `radix`.
|
||||||
|
fn to_str_radix(&self, radix: uint) -> String {
|
||||||
|
format!("{}/{}",
|
||||||
|
self.numer.to_str_radix(radix),
|
||||||
|
self.denom.to_str_radix(radix))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: FromStr + Clone + Integer + PartialOrd>
|
||||||
|
FromStr for Ratio<T> {
|
||||||
|
/// Parses `numer/denom` or just `numer`.
|
||||||
|
fn from_str(s: &str) -> Option<Ratio<T>> {
|
||||||
|
let mut split = s.splitn(1, '/');
|
||||||
|
|
||||||
|
let num = split.next().and_then(|n| FromStr::from_str(n));
|
||||||
|
let den = split.next().or(Some("1")).and_then(|d| FromStr::from_str(d));
|
||||||
|
|
||||||
|
match (num, den) {
|
||||||
|
(Some(n), Some(d)) => Some(Ratio::new(n, d)),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: FromStrRadix + Clone + Integer + PartialOrd>
|
||||||
|
FromStrRadix for Ratio<T> {
|
||||||
|
/// Parses `numer/denom` where the numbers are in base `radix`.
|
||||||
|
fn from_str_radix(s: &str, radix: uint) -> Option<Ratio<T>> {
|
||||||
|
let split: Vec<&str> = s.splitn(1, '/').collect();
|
||||||
|
if split.len() < 2 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let a_option: Option<T> = FromStrRadix::from_str_radix(
|
||||||
|
*split.get(0),
|
||||||
|
radix);
|
||||||
|
a_option.and_then(|a| {
|
||||||
|
let b_option: Option<T> =
|
||||||
|
FromStrRadix::from_str_radix(*split.get(1), radix);
|
||||||
|
b_option.and_then(|b| {
|
||||||
|
Some(Ratio::new(a.clone(), b.clone()))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
|
||||||
|
use super::{Ratio, Rational, BigRational};
|
||||||
|
use std::num::{Zero, One, FromStrRadix, FromPrimitive, ToStrRadix};
|
||||||
|
use std::from_str::FromStr;
|
||||||
|
use std::hash::hash;
|
||||||
|
use std::num;
|
||||||
|
|
||||||
|
pub static _0 : Rational = Ratio { numer: 0, denom: 1};
|
||||||
|
pub static _1 : Rational = Ratio { numer: 1, denom: 1};
|
||||||
|
pub static _2: Rational = Ratio { numer: 2, denom: 1};
|
||||||
|
pub static _1_2: Rational = Ratio { numer: 1, denom: 2};
|
||||||
|
pub static _3_2: Rational = Ratio { numer: 3, denom: 2};
|
||||||
|
pub static _neg1_2: Rational = Ratio { numer: -1, denom: 2};
|
||||||
|
pub static _1_3: Rational = Ratio { numer: 1, denom: 3};
|
||||||
|
pub static _neg1_3: Rational = Ratio { numer: -1, denom: 3};
|
||||||
|
pub static _2_3: Rational = Ratio { numer: 2, denom: 3};
|
||||||
|
pub static _neg2_3: Rational = Ratio { numer: -2, denom: 3};
|
||||||
|
|
||||||
|
pub fn to_big(n: Rational) -> BigRational {
|
||||||
|
Ratio::new(
|
||||||
|
FromPrimitive::from_int(n.numer).unwrap(),
|
||||||
|
FromPrimitive::from_int(n.denom).unwrap()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_test_constants() {
|
||||||
|
// check our constants are what Ratio::new etc. would make.
|
||||||
|
assert_eq!(_0, Zero::zero());
|
||||||
|
assert_eq!(_1, One::one());
|
||||||
|
assert_eq!(_2, Ratio::from_integer(2i));
|
||||||
|
assert_eq!(_1_2, Ratio::new(1i,2i));
|
||||||
|
assert_eq!(_3_2, Ratio::new(3i,2i));
|
||||||
|
assert_eq!(_neg1_2, Ratio::new(-1i,2i));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_new_reduce() {
|
||||||
|
let one22 = Ratio::new(2i,2);
|
||||||
|
|
||||||
|
assert_eq!(one22, One::one());
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
#[should_fail]
|
||||||
|
fn test_new_zero() {
|
||||||
|
let _a = Ratio::new(1i,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cmp() {
|
||||||
|
assert!(_0 == _0 && _1 == _1);
|
||||||
|
assert!(_0 != _1 && _1 != _0);
|
||||||
|
assert!(_0 < _1 && !(_1 < _0));
|
||||||
|
assert!(_1 > _0 && !(_0 > _1));
|
||||||
|
|
||||||
|
assert!(_0 <= _0 && _1 <= _1);
|
||||||
|
assert!(_0 <= _1 && !(_1 <= _0));
|
||||||
|
|
||||||
|
assert!(_0 >= _0 && _1 >= _1);
|
||||||
|
assert!(_1 >= _0 && !(_0 >= _1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_to_integer() {
|
||||||
|
assert_eq!(_0.to_integer(), 0);
|
||||||
|
assert_eq!(_1.to_integer(), 1);
|
||||||
|
assert_eq!(_2.to_integer(), 2);
|
||||||
|
assert_eq!(_1_2.to_integer(), 0);
|
||||||
|
assert_eq!(_3_2.to_integer(), 1);
|
||||||
|
assert_eq!(_neg1_2.to_integer(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_numer() {
|
||||||
|
assert_eq!(_0.numer(), &0);
|
||||||
|
assert_eq!(_1.numer(), &1);
|
||||||
|
assert_eq!(_2.numer(), &2);
|
||||||
|
assert_eq!(_1_2.numer(), &1);
|
||||||
|
assert_eq!(_3_2.numer(), &3);
|
||||||
|
assert_eq!(_neg1_2.numer(), &(-1));
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_denom() {
|
||||||
|
assert_eq!(_0.denom(), &1);
|
||||||
|
assert_eq!(_1.denom(), &1);
|
||||||
|
assert_eq!(_2.denom(), &1);
|
||||||
|
assert_eq!(_1_2.denom(), &2);
|
||||||
|
assert_eq!(_3_2.denom(), &2);
|
||||||
|
assert_eq!(_neg1_2.denom(), &2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_is_integer() {
|
||||||
|
assert!(_0.is_integer());
|
||||||
|
assert!(_1.is_integer());
|
||||||
|
assert!(_2.is_integer());
|
||||||
|
assert!(!_1_2.is_integer());
|
||||||
|
assert!(!_3_2.is_integer());
|
||||||
|
assert!(!_neg1_2.is_integer());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_show() {
|
||||||
|
assert_eq!(format!("{}", _2), "2".to_string());
|
||||||
|
assert_eq!(format!("{}", _1_2), "1/2".to_string());
|
||||||
|
assert_eq!(format!("{}", _0), "0".to_string());
|
||||||
|
assert_eq!(format!("{}", Ratio::from_integer(-2i)), "-2".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
mod arith {
|
||||||
|
use super::{_0, _1, _2, _1_2, _3_2, _neg1_2, to_big};
|
||||||
|
use super::super::{Ratio, Rational};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_add() {
|
||||||
|
fn test(a: Rational, b: Rational, c: Rational) {
|
||||||
|
assert_eq!(a + b, c);
|
||||||
|
assert_eq!(to_big(a) + to_big(b), to_big(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
test(_1, _1_2, _3_2);
|
||||||
|
test(_1, _1, _2);
|
||||||
|
test(_1_2, _3_2, _2);
|
||||||
|
test(_1_2, _neg1_2, _0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sub() {
|
||||||
|
fn test(a: Rational, b: Rational, c: Rational) {
|
||||||
|
assert_eq!(a - b, c);
|
||||||
|
assert_eq!(to_big(a) - to_big(b), to_big(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
test(_1, _1_2, _1_2);
|
||||||
|
test(_3_2, _1_2, _1);
|
||||||
|
test(_1, _neg1_2, _3_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mul() {
|
||||||
|
fn test(a: Rational, b: Rational, c: Rational) {
|
||||||
|
assert_eq!(a * b, c);
|
||||||
|
assert_eq!(to_big(a) * to_big(b), to_big(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
test(_1, _1_2, _1_2);
|
||||||
|
test(_1_2, _3_2, Ratio::new(3i,4i));
|
||||||
|
test(_1_2, _neg1_2, Ratio::new(-1i, 4i));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_div() {
|
||||||
|
fn test(a: Rational, b: Rational, c: Rational) {
|
||||||
|
assert_eq!(a / b, c);
|
||||||
|
assert_eq!(to_big(a) / to_big(b), to_big(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
test(_1, _1_2, _2);
|
||||||
|
test(_3_2, _1_2, _1 + _2);
|
||||||
|
test(_1, _neg1_2, _neg1_2 + _neg1_2 + _neg1_2 + _neg1_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rem() {
|
||||||
|
fn test(a: Rational, b: Rational, c: Rational) {
|
||||||
|
assert_eq!(a % b, c);
|
||||||
|
assert_eq!(to_big(a) % to_big(b), to_big(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
test(_3_2, _1, _1_2);
|
||||||
|
test(_2, _neg1_2, _0);
|
||||||
|
test(_1_2, _2, _1_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_neg() {
|
||||||
|
fn test(a: Rational, b: Rational) {
|
||||||
|
assert_eq!(-a, b);
|
||||||
|
assert_eq!(-to_big(a), to_big(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
test(_0, _0);
|
||||||
|
test(_1_2, _neg1_2);
|
||||||
|
test(-_1, _1);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_zero() {
|
||||||
|
assert_eq!(_0 + _0, _0);
|
||||||
|
assert_eq!(_0 * _0, _0);
|
||||||
|
assert_eq!(_0 * _1, _0);
|
||||||
|
assert_eq!(_0 / _neg1_2, _0);
|
||||||
|
assert_eq!(_0 - _0, _0);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
#[should_fail]
|
||||||
|
fn test_div_0() {
|
||||||
|
let _a = _1 / _0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_round() {
|
||||||
|
assert_eq!(_1_3.ceil(), _1);
|
||||||
|
assert_eq!(_1_3.floor(), _0);
|
||||||
|
assert_eq!(_1_3.round(), _0);
|
||||||
|
assert_eq!(_1_3.trunc(), _0);
|
||||||
|
|
||||||
|
assert_eq!(_neg1_3.ceil(), _0);
|
||||||
|
assert_eq!(_neg1_3.floor(), -_1);
|
||||||
|
assert_eq!(_neg1_3.round(), _0);
|
||||||
|
assert_eq!(_neg1_3.trunc(), _0);
|
||||||
|
|
||||||
|
assert_eq!(_2_3.ceil(), _1);
|
||||||
|
assert_eq!(_2_3.floor(), _0);
|
||||||
|
assert_eq!(_2_3.round(), _1);
|
||||||
|
assert_eq!(_2_3.trunc(), _0);
|
||||||
|
|
||||||
|
assert_eq!(_neg2_3.ceil(), _0);
|
||||||
|
assert_eq!(_neg2_3.floor(), -_1);
|
||||||
|
assert_eq!(_neg2_3.round(), -_1);
|
||||||
|
assert_eq!(_neg2_3.trunc(), _0);
|
||||||
|
|
||||||
|
assert_eq!(_1_2.ceil(), _1);
|
||||||
|
assert_eq!(_1_2.floor(), _0);
|
||||||
|
assert_eq!(_1_2.round(), _1);
|
||||||
|
assert_eq!(_1_2.trunc(), _0);
|
||||||
|
|
||||||
|
assert_eq!(_neg1_2.ceil(), _0);
|
||||||
|
assert_eq!(_neg1_2.floor(), -_1);
|
||||||
|
assert_eq!(_neg1_2.round(), -_1);
|
||||||
|
assert_eq!(_neg1_2.trunc(), _0);
|
||||||
|
|
||||||
|
assert_eq!(_1.ceil(), _1);
|
||||||
|
assert_eq!(_1.floor(), _1);
|
||||||
|
assert_eq!(_1.round(), _1);
|
||||||
|
assert_eq!(_1.trunc(), _1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fract() {
|
||||||
|
assert_eq!(_1.fract(), _0);
|
||||||
|
assert_eq!(_neg1_2.fract(), _neg1_2);
|
||||||
|
assert_eq!(_1_2.fract(), _1_2);
|
||||||
|
assert_eq!(_3_2.fract(), _1_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_recip() {
|
||||||
|
assert_eq!(_1 * _1.recip(), _1);
|
||||||
|
assert_eq!(_2 * _2.recip(), _1);
|
||||||
|
assert_eq!(_1_2 * _1_2.recip(), _1);
|
||||||
|
assert_eq!(_3_2 * _3_2.recip(), _1);
|
||||||
|
assert_eq!(_neg1_2 * _neg1_2.recip(), _1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_to_from_str() {
|
||||||
|
fn test(r: Rational, s: String) {
|
||||||
|
assert_eq!(FromStr::from_str(s.as_slice()), Some(r));
|
||||||
|
assert_eq!(r.to_string(), s);
|
||||||
|
}
|
||||||
|
test(_1, "1".to_string());
|
||||||
|
test(_0, "0".to_string());
|
||||||
|
test(_1_2, "1/2".to_string());
|
||||||
|
test(_3_2, "3/2".to_string());
|
||||||
|
test(_2, "2".to_string());
|
||||||
|
test(_neg1_2, "-1/2".to_string());
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_from_str_fail() {
|
||||||
|
fn test(s: &str) {
|
||||||
|
let rational: Option<Rational> = FromStr::from_str(s);
|
||||||
|
assert_eq!(rational, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let xs = ["0 /1", "abc", "", "1/", "--1/2","3/2/1"];
|
||||||
|
for &s in xs.iter() {
|
||||||
|
test(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_to_from_str_radix() {
|
||||||
|
fn test(r: Rational, s: String, n: uint) {
|
||||||
|
assert_eq!(FromStrRadix::from_str_radix(s.as_slice(), n),
|
||||||
|
Some(r));
|
||||||
|
assert_eq!(r.to_str_radix(n).to_string(), s);
|
||||||
|
}
|
||||||
|
fn test3(r: Rational, s: String) { test(r, s, 3) }
|
||||||
|
fn test16(r: Rational, s: String) { test(r, s, 16) }
|
||||||
|
|
||||||
|
test3(_1, "1/1".to_string());
|
||||||
|
test3(_0, "0/1".to_string());
|
||||||
|
test3(_1_2, "1/2".to_string());
|
||||||
|
test3(_3_2, "10/2".to_string());
|
||||||
|
test3(_2, "2/1".to_string());
|
||||||
|
test3(_neg1_2, "-1/2".to_string());
|
||||||
|
test3(_neg1_2 / _2, "-1/11".to_string());
|
||||||
|
|
||||||
|
test16(_1, "1/1".to_string());
|
||||||
|
test16(_0, "0/1".to_string());
|
||||||
|
test16(_1_2, "1/2".to_string());
|
||||||
|
test16(_3_2, "3/2".to_string());
|
||||||
|
test16(_2, "2/1".to_string());
|
||||||
|
test16(_neg1_2, "-1/2".to_string());
|
||||||
|
test16(_neg1_2 / _2, "-1/4".to_string());
|
||||||
|
test16(Ratio::new(13i,15i), "d/f".to_string());
|
||||||
|
test16(_1_2*_1_2*_1_2*_1_2, "1/10".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_str_radix_fail() {
|
||||||
|
fn test(s: &str) {
|
||||||
|
let radix: Option<Rational> = FromStrRadix::from_str_radix(s, 3);
|
||||||
|
assert_eq!(radix, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let xs = ["0 /1", "abc", "", "1/", "--1/2","3/2/1", "3/2"];
|
||||||
|
for &s in xs.iter() {
|
||||||
|
test(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_float() {
|
||||||
|
fn test<T: Float>(given: T, (numer, denom): (&str, &str)) {
|
||||||
|
let ratio: BigRational = Ratio::from_float(given).unwrap();
|
||||||
|
assert_eq!(ratio, Ratio::new(
|
||||||
|
FromStr::from_str(numer).unwrap(),
|
||||||
|
FromStr::from_str(denom).unwrap()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// f32
|
||||||
|
test(3.14159265359f32, ("13176795", "4194304"));
|
||||||
|
test(2f32.powf(100.), ("1267650600228229401496703205376", "1"));
|
||||||
|
test(-2f32.powf(100.), ("-1267650600228229401496703205376", "1"));
|
||||||
|
test(1.0 / 2f32.powf(100.), ("1", "1267650600228229401496703205376"));
|
||||||
|
test(684729.48391f32, ("1369459", "2"));
|
||||||
|
test(-8573.5918555f32, ("-4389679", "512"));
|
||||||
|
|
||||||
|
// f64
|
||||||
|
test(3.14159265359f64, ("3537118876014453", "1125899906842624"));
|
||||||
|
test(2f64.powf(100.), ("1267650600228229401496703205376", "1"));
|
||||||
|
test(-2f64.powf(100.), ("-1267650600228229401496703205376", "1"));
|
||||||
|
test(684729.48391f64, ("367611342500051", "536870912"));
|
||||||
|
test(-8573.5918555f64, ("-4713381968463931", "549755813888"));
|
||||||
|
test(1.0 / 2f64.powf(100.), ("1", "1267650600228229401496703205376"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_float_fail() {
|
||||||
|
use std::{f32, f64};
|
||||||
|
|
||||||
|
assert_eq!(Ratio::from_float(f32::NAN), None);
|
||||||
|
assert_eq!(Ratio::from_float(f32::INFINITY), None);
|
||||||
|
assert_eq!(Ratio::from_float(f32::NEG_INFINITY), None);
|
||||||
|
assert_eq!(Ratio::from_float(f64::NAN), None);
|
||||||
|
assert_eq!(Ratio::from_float(f64::INFINITY), None);
|
||||||
|
assert_eq!(Ratio::from_float(f64::NEG_INFINITY), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_signed() {
|
||||||
|
assert_eq!(_neg1_2.abs(), _1_2);
|
||||||
|
assert_eq!(_3_2.abs_sub(&_1_2), _1);
|
||||||
|
assert_eq!(_1_2.abs_sub(&_3_2), Zero::zero());
|
||||||
|
assert_eq!(_1_2.signum(), One::one());
|
||||||
|
assert_eq!(_neg1_2.signum(), - num::one::<Ratio<int>>());
|
||||||
|
assert!(_neg1_2.is_negative());
|
||||||
|
assert!(! _neg1_2.is_positive());
|
||||||
|
assert!(! _1_2.is_negative());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hash() {
|
||||||
|
assert!(hash(&_0) != hash(&_1));
|
||||||
|
assert!(hash(&_0) != hash(&_3_2));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue