1#![no_std]
18#![feature(core_intrinsics)]
19
20extern crate core as std;
21
22use std::intrinsics::{fadd_fast, fsub_fast, fmul_fast, fdiv_fast, frem_fast};
23use std::ops::{
24 Add,
25 Sub,
26 Mul,
27 Div,
28 Rem,
29 AddAssign,
30 SubAssign,
31 MulAssign,
32 DivAssign,
33 RemAssign,
34};
35
36#[derive(Copy, Clone, PartialEq, PartialOrd)]
41#[repr(transparent)]
42pub struct Fast<F>(F);
43
44pub type FF64 = Fast<f64>;
46pub type FF32 = Fast<f32>;
48
49impl<F> Fast<F> {
50 pub unsafe fn new(value: F) -> Self { Fast(value) }
61
62 pub fn get(self) -> F { self.0 }
64}
65
66impl Into<f32> for Fast<f32> {
67 fn into(self: Self) -> f32 { self.get() }
68}
69
70impl Into<f64> for Fast<f64> {
71 fn into(self: Self) -> f64 { self.get() }
72}
73
74macro_rules! impl_op {
75 ($($name:ident, $method:ident, $intrins:ident;)*) => {
76 $(
77 impl $name<f64> for Fast<f64> {
79 type Output = Self;
80 #[inline(always)]
81 fn $method(self, rhs: f64) -> Self::Output {
82 unsafe {
83 Fast($intrins(self.0, rhs))
84 }
85 }
86 }
87
88 impl $name<f32> for Fast<f32> {
89 type Output = Self;
90 #[inline(always)]
91 fn $method(self, rhs: f32) -> Self::Output {
92 unsafe {
93 Fast($intrins(self.0, rhs))
94 }
95 }
96 }
97
98 impl $name<Fast<f64>> for f64 {
100 type Output = Fast<f64>;
101 #[inline(always)]
102 fn $method(self, rhs: Fast<f64>) -> Self::Output {
103 Fast(self).$method(rhs.0)
104 }
105 }
106
107 impl $name<Fast<f32>> for f32 {
108 type Output = Fast<f32>;
109 #[inline(always)]
110 fn $method(self, rhs: Fast<f32>) -> Self::Output {
111 Fast(self).$method(rhs.0)
112 }
113 }
114
115 impl $name for Fast<f64> {
117 type Output = Self;
118 #[inline(always)]
119 fn $method(self, rhs: Self) -> Self::Output {
120 self.$method(rhs.0)
121 }
122 }
123
124 impl $name for Fast<f32> {
125 type Output = Self;
126 #[inline(always)]
127 fn $method(self, rhs: Self) -> Self::Output {
128 self.$method(rhs.0)
129 }
130 }
131 )*
132
133 }
134}
135
136macro_rules! impl_assignop {
137 ($($name:ident, $method:ident, $optrt:ident, $opmth:ident;)*) => {
138 $(
139 impl<F, Rhs> $name<Rhs> for Fast<F>
140 where Self: $optrt<Rhs, Output=Self> + Copy,
141 {
142 #[inline(always)]
143 fn $method(&mut self, rhs: Rhs) {
144 *self = (*self).$opmth(rhs)
145 }
146 }
147 )*
148
149 }
150}
151
152impl_op! {
153 Add, add, fadd_fast;
154 Sub, sub, fsub_fast;
155 Mul, mul, fmul_fast;
156 Div, div, fdiv_fast;
157 Rem, rem, frem_fast;
158}
159
160impl_assignop! {
161 AddAssign, add_assign, Add, add;
162 SubAssign, sub_assign, Sub, sub;
163 MulAssign, mul_assign, Mul, mul;
164 DivAssign, div_assign, Div, div;
165 RemAssign, rem_assign, Rem, rem;
166}
167
168use std::fmt;
169macro_rules! impl_format {
170 ($($name:ident)+) => {
171 $(
172 impl<F: fmt::$name> fmt::$name for Fast<F> {
173 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174 self.0.fmt(f)
175 }
176 }
177 )+
178 }
179}
180
181impl_format!(Debug Display LowerExp UpperExp);
182
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187
188 macro_rules! test_op {
189 ($($op:tt)+) => {
190 $(
191 assert_eq!(Fast(2.) $op Fast(1.), Fast(2. $op 1.));
192 )+
193 }
194 }
195
196 #[test]
197 fn each_op() {
198 test_op!(+ - * / %);
199 }
200
201 macro_rules! assign_op {
202 ($($x:literal $op:tt $y:literal is $z:literal ;)+) => {
203 $(
204 let mut x = Fast($x);
205 x $op Fast($y);
206 assert_eq!(x, Fast($z));
207 )+
208 }
209 }
210
211 #[test]
212 fn assign_ops() {
213 assign_op!(
214 1. += 2. is 3.;
215 1. -= 2. is -1.;
216 2. *= 2. is 4.;
217 2. /= 2. is 1.;
218 5. %= 2. is 1.;
219 );
220 }
221}