1 // Written in the D programming language. 2 /* 3 NYSL Version 0.9982 4 5 A. This software is "Everyone'sWare". It means: 6 Anybody who has this software can use it as if he/she is 7 the author. 8 9 A-1. Freeware. No fee is required. 10 A-2. You can freely redistribute this software. 11 A-3. You can freely modify this software. And the source 12 may be used in any software with no limitation. 13 A-4. When you release a modified version to public, you 14 must publish it with your name. 15 16 B. The author is not responsible for any kind of damages or loss 17 while using or misusing this software, which is distributed 18 "AS IS". No warranty of any kind is expressed or implied. 19 You use AT YOUR OWN RISK. 20 21 C. Copyrighted to Kazuki KOMATSU 22 23 D. Above three clauses are applied both to source and binary 24 form of this software. 25 */ 26 27 /** 28 このモジュールは、標準ライブラリstd.mathの拡張です。 29 */ 30 module carbon.math; 31 32 import std.math; 33 import std.traits; 34 import std.array; 35 import std.range; 36 import std.typecons; 37 38 39 real toDeg(real rad) pure nothrow @safe 40 { 41 return rad / PI * 180; 42 } 43 44 45 real toRad(real deg) pure nothrow @safe 46 { 47 return deg / 180 * PI; 48 } 49 50 51 bool isPowOf2(I)(I n) 52 if(is(typeof(n && (n & (n-1)) == 0 ))) 53 { 54 return n && (n & (n-1)) == 0; 55 } 56 57 unittest{ 58 assert(!0.isPowOf2); 59 assert( 1.isPowOf2); 60 assert( 2.isPowOf2); 61 assert( 4.isPowOf2); 62 assert(!6.isPowOf2); 63 assert( 8.isPowOf2); 64 assert(!9.isPowOf2); 65 assert(!10.isPowOf2); 66 } 67 68 69 T sqrtFloor(T, F)(F x) 70 if(isFloatingPoint!F) 71 { 72 return cast(T)(sqrt(x)); 73 } 74 75 76 T sqrtCeil(T, F)(F x) 77 if(isFloatingPoint!F) 78 { 79 return cast(T)(sqrt(x).ceil()); 80 } 81 82 83 T lcm(T)(T x, T y) 84 { 85 return x * (y / gcd(x, y)); 86 } 87 88 89 pure bool isPrime(T)(T src)if(__traits(isIntegral,T)){ 90 if(src <= 1)return false; 91 else if(src < 4)return true; 92 else if(!(src&1))return false; 93 else if(((src+1)%6) && ((src-1)%6))return false; 94 95 T root = cast(T)sqrt(cast(real)src) + 1; 96 97 for(T i = 5; i < root; i += 6) 98 if(!((src%i) && ((src)%(i+2)))) 99 return false; 100 101 return true; 102 } 103 104 105 void primeFactors(T, R)(T n, ref R or) 106 if(isOutputRange!(R, Tuple!(T, uint))) 107 { 108 alias E = Tuple!(T, uint); 109 110 if(n < 0){ 111 primeFactors(-n, or); 112 return; 113 } 114 115 if(n <= 1){ 116 return; 117 } 118 119 import core.bitop; 120 121 static if(is(T == long) || is(T == ulong)) 122 { 123 { 124 uint cnt; 125 immutable uint lns = n & uint.max; 126 if(auto c = bsf(lns)) 127 cnt = c; 128 else if(lns == 0) 129 cnt = bsf(cast(uint)(n >> 32)) + 32; 130 131 if(cnt){ 132 put(or, E(2, cnt)); 133 n >>= cnt; 134 } 135 } 136 } 137 else 138 { 139 if(auto cnt = bsf(n)){ 140 put(or, E(2, cnt)); 141 n >>= cnt; 142 } 143 } 144 145 if(isPrime(n)){ 146 put(or, E(n, 1)); 147 return; 148 } 149 150 // Fermat's method 151 { 152 T x = cast(T)sqrt(cast(real)n), 153 y = 0; 154 155 T diff = x^^2 - n; 156 { 157 T cnt = 3; 158 bool sw; 159 while(diff != 0){ 160 if(n % cnt == 0){ 161 // p = n / cnt, q = cnt 162 auto p = n / cnt; 163 x = (p + cnt) / 2; 164 y = (p - cnt) / 2; 165 diff = 0; 166 break; 167 } 168 cnt += 2; 169 170 if(diff < 0){ 171 diff += 2*x + 1; 172 ++x; 173 }else if(!sw && diff > 2*y+1){ 174 auto m = cast(T)ceil(sqrt((cast(real)y)^^2 + diff) - y); 175 diff -= m * (m + 2 * y); 176 y += m; 177 }else{ 178 sw = true; 179 diff -= 2*y + 1; 180 ++y; 181 } 182 } 183 } 184 185 T p = x + y, 186 q = x - y; 187 188 if(p == q){ 189 auto dlg = (E e){ 190 e[1] *= 2; 191 put(or, e); 192 }; 193 194 primeFactors(p, dlg); 195 return; 196 } 197 198 if(isPrime(q)){ 199 uint c = 1; 200 while(p % q == 0){ 201 p /= q; 202 ++c; 203 } 204 205 put(or, E(q, c)); 206 }else{ 207 { 208 auto dlg = (E e){ 209 while(p % e[0] == 0){ 210 p /= e[0]; 211 ++e[1]; 212 } 213 214 put(or, e); 215 }; 216 217 primeFactors(q, dlg); 218 } 219 } 220 221 primeFactors(p, or); 222 } 223 } 224 225 226 Tuple!(T, uint)[] primeFactors(T)(T n) 227 { 228 auto app = appender!(typeof(return))(); 229 primeFactors(n, app); 230 return app.data; 231 } 232 233 234 unittest 235 { 236 foreach(n; 2 .. 100000){ 237 ulong m = 1; 238 foreach(ps; primeFactors(n)) 239 m *= ps[0] ^^ ps[1]; 240 241 assert(m == n); 242 } 243 244 foreach(n; 10_000_000L .. 10_001_000L){ 245 ulong m = 1; 246 foreach(ps; primeFactors(n)) 247 m *= ps[0] ^^ ps[1]; 248 249 assert(m == n); 250 } 251 } 252 253 254 void primeFactorsSimple(T, R)(T n, ref R or) 255 if(isOutputRange!(R, Tuple!(T, uint))) 256 { 257 alias E = Tuple!(T, uint); 258 T m = 2; 259 while(n != 1){ 260 if(isPrime(n)){ 261 put(or, E(n, 1)); 262 return; 263 } 264 265 uint c; 266 while(n % m == 0){ 267 n /= m; 268 ++c; 269 } 270 271 if(c) put(or, E(m, c)); 272 ++m; 273 } 274 } 275 276 277 Tuple!(T, uint)[] primeFactorsSimple(T)(T n) 278 { 279 auto app = appender!(typeof(return))(); 280 primeFactorsSimple(n, app); 281 return app.data; 282 } 283 284 285 unittest 286 { 287 foreach(n; 2 .. 100000){ 288 ulong m = 1; 289 foreach(ps; primeFactorsSimple(n)) 290 m *= ps[0] ^^ ps[1]; 291 292 assert(m == n); 293 } 294 295 foreach(n; 10_000_000L .. 10_001_000L){ 296 ulong m = 1; 297 foreach(ps; primeFactorsSimple(n)) 298 m *= ps[0] ^^ ps[1]; 299 300 assert(m == n); 301 } 302 }