| 119 | // Rough approximation of the length. |
| 120 | fixed Length_approx() const |
| 121 | { |
| 122 | // CORDIC algorithm: Rotate (x,y) onto the x-axis and use the new x as an approximation of the length. |
| 123 | |
| 124 | // TODO: Choose an appropriate value of max_loop_var. |
| 125 | // Error: N := max_loop_var - 1, emax_rel = 1 - cos(arctan(1/2^N)) = 1 - 1/sqrt(1+4^(-N)) |
| 126 | // In this case: Rel. error <= emax_rel (N=7) ~ 3*10^-5 |
| 127 | |
| 128 | const i32 max_loop_var = 8; |
| 129 | // Because we use multiples of rotation matrices, we need to scale the result. |
| 130 | // Factor = Product of (1+4^(-n))^(-1/2) from 0 to max_loop_var - 1. |
| 131 | // The factor below is (obviously) only right for max_loop_var = 8. |
| 132 | CFixed_15_16 corr_factor = CFixed_15_16::FromDouble(0.60725911229889273006029454182250359069); |
| 133 | |
| 134 | i32 x = X.GetInternalValue(); |
| 135 | i32 y = Y.GetInternalValue(); |
| 136 | // We want x >= 0. |
| 137 | // TODO: Further optimizations. |
| 138 | if (x < 0) |
| 139 | x *= -1; |
| 140 | |
| 141 | i32 tmp; |
| 142 | for (u8 loop_var = 0; loop_var < max_loop_var; ++loop_var) |
| 143 | { |
| 144 | tmp = x >> loop_var; |
| 145 | if(y < 0) |
| 146 | { |
| 147 | // (x,y) -> (x,y) + 1/2^n * (-y,x) |
| 148 | x -= y >> loop_var; |
| 149 | y += tmp; |
| 150 | } |
| 151 | else |
| 152 | { |
| 153 | // (x,y) -> (x,y) + 1/2^n * (y,-x) |
| 154 | x += y >> loop_var; |
| 155 | y -= tmp; |
| 156 | } |
| 157 | } |
| 158 | CFixed_15_16 result; |
| 159 | result.SetInternalValue(x); |
| 160 | return result.Multiply(corr_factor); |
| 161 | } |
| 162 | |