1 /// Author: Aziz Köksal
2 /// License: GPL3
3 /// $(Maturity average)
4 module dil.Float;
5 
6 import common;
7 
8 // Used to be a wrapper class for the MPFR library functions.
9 // However, it was changed because the dependency has been a huge annoyance:
10 // * No up-to-date pre-compiled lib for Windows (let alone other platforms);
11 // * Can't be sure if the D mpfr struct has the correct size
12 
13 /// A multiprecision float. TODO: needs to be implemented using BigInt.
14 /// Macros:
15 /// f = <a href="#Float.f" style="text-decoration:none">f</a>
16 class Float
17 {
18   real f; /// Implemented using a 'real' for now.
19 
20   /// Constructs a Float initialized to NaN.
21   this()
22   {
23   }
24 
25   /// Constructs from a Float. Copies x.
26   this(Float x)
27   {
28     f = x.f;
29   }
30 
31   /// Constructs from a real.
32   this(real x)
33   {
34     f = x;
35   }
36 
37   /// Constructs from an int.
38   this(int x)
39   {
40     this(cast(long)x);
41   }
42 
43   /// Constructs from a uint.
44   this(uint x)
45   {
46     this(cast(ulong)x);
47   }
48 
49   /// Constructs from a long.
50   this(long x)
51   {
52     f = x;
53   }
54 
55   /// Constructs from a ulong.
56   this(ulong x)
57   {
58     f = x;
59   }
60 
61   /// Constructs from a double.
62   this(double x)
63   {
64     f = x;
65   }
66 
67   /// Constructs from a string.
68   this(cstring x, int base = 10)
69   {
70     if (!x.length)
71       this();
72     else
73     {
74       if (x[$-1] != '\0')
75         x = x ~ '\0'; // Terminate with zero
76       this(x.ptr, base);
77     }
78   }
79 
80   /// Constructs from a zero-terminated string.
81   this(cchar* x, int base = 10)
82   {
83     // TODO:
84   }
85 
86   /// Constructs from a string and outputs a precision return code.
87   this(out int retcode, cstring str)
88   {
89     // TODO:
90   }
91 
92   /// For convenient construction of Floats.
93   static Float opCall(Params...)(Params P)
94   {
95     return new Float(P);
96   }
97 
98   /// Returns a deep copy of this number.
99   Float dup()
100   {
101     return new Float(this);
102   }
103 
104   /// Returns true for an infinite number.
105   bool isInf()
106   {
107     // TODO:
108     return false;
109   }
110 
111   /// Returns true for positive infinity.
112   bool isPInf()
113   {
114     // TODO:
115     return false;
116   }
117 
118   /// Returns true for negative infinity.
119   bool isNInf()
120   {
121     // TODO:
122     return false;
123   }
124 
125   /// Returns true for a NaN.
126   bool isNaN()
127   {
128     // TODO:
129     return false;
130   }
131 
132   /// Returns true for zero.
133   bool isZero()
134   {
135     // TODO:
136     return false;
137   }
138 
139   // TODO: add set() methods.
140 
141   /// Calculates $(f) += x.
142   Float opAddAssign(Float x)
143   {
144     f += x.f;
145     return this;
146   }
147 
148   /// Calculates $(f) += x.
149   Float opAddAssign(uint x)
150   {
151     f += x;
152     return this;
153   }
154 
155   /// Calculates $(f) + x.
156   Float opAdd(T)(T x)
157   {
158     static if (is(T == Float) || is(T == uint))
159       return dup() += x;
160     else
161       return dup() += new Float(x);
162   }
163 
164   /// Calculates $(f) -= x.
165   Float opSubAssign(Float x)
166   {
167     f -= x.f;
168     return this;
169   }
170 
171   /// Calculates $(f) -= x.
172   Float opSubAssign(uint x)
173   {
174     f -= x;
175     return this;
176   }
177 
178   /// Calculates $(f) - x.
179   Float opSub(T)(T x)
180   {
181     static if (is(T == Float) || is(T == uint))
182       return dup() -= x;
183     else
184       return dup() -= new Float(x);
185   }
186 
187   /// Calculates x - $(f).
188   Float opSub_r(uint x)
189   {
190     return new Float(x - f);
191   }
192 
193   /// Calculates $(f) /= x.
194   Float opDivAssign(Float x)
195   {
196     f /= x.f;
197     return this;
198   }
199 
200   /// Calculates $(f) /= x.
201   Float opDivAssign(uint x)
202   {
203     f /= x;
204     return this;
205   }
206 
207   /// Calculates $(f) / x.
208   Float opDiv(T)(T x)
209   {
210     static if (is(T == Float) || is(T == uint))
211       return dup() /= x;
212     else
213       return dup() /= new Float(x);
214   }
215 
216   /// Calculates x / $(f).
217   Float opDiv_r(uint x)
218   {
219     return new Float(x / f);
220   }
221 
222   /// Calculates $(f) %= x.
223   Float opModAssign(Float x)
224   {
225     f %= x.f;
226     return this;
227   }
228 
229   /// Calculates $(f) % x.
230   Float opMod(Float x)
231   {
232     return dup() %= x;
233   }
234 
235   /// Calculates $(f) *= x.
236   Float opMulAssign(Float x)
237   {
238     f *= x.f;
239     return this;
240   }
241 
242   /// Calculates $(f) *= x.
243   Float opMulAssign(uint x)
244   {
245     f *= x;
246     return this;
247   }
248 
249   /// Calculates $(f) * x.
250   Float opMul(T)(T x)
251   {
252     static if (is(T == Float) || is(T == uint))
253       return dup() *= x;
254     else
255       return dup() *= new Float(x);
256   }
257 
258   /// Compares $(f) to x.
259   override bool opEquals(Object x)
260   {
261     if (auto y = cast(Float)x)
262       return opEquals(y);
263     return true;
264   }
265 
266   /// Compares $(f) to x.
267   bool opEquals(Float x)
268   {
269     // TODO:
270     return false;
271   }
272 
273   /// ditto
274   bool opEquals(double x)
275   {
276     // TODO:
277     return false;
278   }
279 
280   /// ditto
281   bool opEquals(int x)
282   {
283     // TODO:
284     return false;
285   }
286 
287   /// ditto
288   bool opEquals(uint x)
289   {
290     // TODO:
291     return false;
292   }
293 
294   alias equals = opEquals;
295 
296   alias opCmp = super.opCmp;
297 
298   /// Compares $(f) to x.
299   int opCmp(Float x)
300   {
301     // TODO:
302     return false;
303   }
304 
305   /// ditto
306   int opCmp(double x)
307   {
308     // TODO:
309     return false;
310   }
311 
312   /// ditto
313   int opCmp(int x)
314   {
315     // TODO:
316     return false;
317   }
318 
319   /// ditto
320   int opCmp(uint x)
321   {
322     // TODO:
323     return false;
324   }
325 
326   /// Returns true if the first bits of $(f) and x are equal.
327   bool equals(Float x, uint bits)
328   {
329     // TODO:
330     return false;
331   }
332 
333   /// Sets $(f) to frac($(f)). Returns itself.
334   Float fraction()
335   {
336     // TODO:
337     return this;
338   }
339 
340   /// Returns a negated copy of this number.
341   Float opNeg()
342   {
343     auto x = dup();
344     x.f = -f;
345     return x;
346   }
347 
348   /// Negates this number.
349   Float neg()
350   {
351     f = -f;
352     return this;
353   }
354 
355   /// Returns true if negative.
356   bool isNeg()
357   {
358     return f < 0;
359   }
360 
361   /// Sets the number to its absolute value. Returns itself.
362   Float abs()
363   {
364     if (f < 0)
365       f = -f;
366     return this;
367   }
368 
369   /// Returns this float as a string.
370   override string toString()
371   {
372     return toString(30).idup;
373   }
374 
375   /// Returns this float as a string.
376   /// Formatted in the scientific representation.
377   char[] toString(uint precision)
378   {
379     // FIXME:
380     return Format("{}", f);
381   }
382 
383   /// Returns the internals of the data structure as a hex string.
384   char[] toHex()
385   {
386     // FIXME:
387     return Format("{:X}", f);
388   }
389 
390   // Exponentiation and logarithmic functions.
391 
392   /// Calculates √$(f). Returns itself.
393   Float sqrt()
394   {
395     // TOOD:
396     return this;
397   }
398 
399   /// Calculates √x. Returns a new Float.
400   static Float sqrt(uint x)
401   {
402     // TODO:
403     return new Float();
404   }
405 
406   /// Calculates $(f)$(SUP x). Returns itself.
407   Float pow(uint x)
408   {
409     // TODO:
410     return this;
411   }
412 
413   /// Calculates $(f)². Returns itself.
414   Float square()
415   {
416     // TODO:
417     return this;
418   }
419 
420   /// Calculates ln(x). Returns itself.
421   Float ln()
422   {
423     // TODO:
424     return this;
425   }
426   /// Calculates log$(SUB 2)(x). Returns itself.
427   Float log2()
428   {
429     // TODO:
430     return this;
431   }
432   /// Calculates log$(SUB 10)(x). Returns itself.
433   Float log10()
434   {
435     // TODO:
436     return this;
437   }
438   /// Calculates e$(SUP x). Returns itself.
439   Float exp()
440   {
441     // TODO:
442     return this;
443   }
444 
445   /// Calculates acos(x). Returns itself.
446   Float acos()
447   {
448     // TODO:
449     return this;
450   }
451 
452   /// Calculates asin(x). Returns itself.
453   Float asin()
454   {
455     // TODO:
456     return this;
457   }
458 
459   /// Calculates atan(x). Returns itself.
460   Float atan()
461   {
462     // TODO:
463     return this;
464   }
465 
466   /// Calculates sin(x). Returns itself.
467   Float sin()
468   {
469     // TODO:
470     return this;
471   }
472 
473   /// Calculates cos(x). Returns itself.
474   Float cos()
475   {
476     // TODO:
477     return this;
478   }
479 
480   /// Calculates tan(x). Returns itself.
481   Float tan()
482   {
483     // TODO:
484     return this;
485   }
486 
487   /// Calculates atan(y/x). Returns itself.
488   Float atan2(Float x)
489   {
490     // TODO:
491     return this;
492   }
493 
494   /// Calculates hypot(x, y) = √(x² + y²). Returns itself.
495   Float hypot(Float y)
496   {
497     // TODO:
498     return this;
499   }
500 }
501 
502 /// Returns ln(x).
503 Float ln(Float x)
504 {
505   return x.dup().ln();
506 }
507 /// Returns log$(SUB 2)(x).
508 Float log2(Float x)
509 {
510   return x.dup().log2();
511 }
512 /// Returns log$(SUB 10)(x).
513 Float log10(Float x)
514 {
515   return x.dup().log10();
516 }
517 /// Returns e$(SUP x).
518 Float exp(Float x)
519 {
520   return x.dup().exp();
521 }
522 
523 /// Returns acos(x).
524 Float acos(Float x)
525 {
526   return x.dup().acos();
527 }
528 /// Returns asin(x).
529 Float asin(Float x)
530 {
531   return x.dup().asin();
532 }
533 /// Returns atan(x).
534 Float atan(Float x)
535 {
536   return x.dup().atan();
537 }
538 /// Returns sin(x).
539 Float sin(Float x)
540 {
541   return x.dup().sin();
542 }
543 /// Returns cos(x).
544 Float cos(Float x)
545 {
546   return x.dup().cos();
547 }
548 /// Returns tan(x).
549 Float tan(Float x)
550 {
551   return x.dup().tan();
552 }
553 /// Returns atan2(x,y) = atan(y/x).
554 Float atan2(Float y, Float x)
555 {
556   return y.dup().atan2(x);
557 }
558 /// Returns hypot(x) = √(x² + y²).
559 Float hypot(Float x, Float y)
560 {
561   return x.dup().hypot(y);
562 }
563 
564 
565 void testFloat()
566 {
567   return; // Remove when Float is fixed.
568   scope msg = new UnittestMsg("Testing class Float.");
569 
570   alias F = Float;
571 
572   assert(F() == 0);
573   assert(F("").toString() == "0");
574   assert(F("0").toString() == "0");
575   assert(F("1.125").toString() == "1.125");
576 
577   size_t i = "123456789".length,
578          n = 1;
579   for (; i < i.max; (i--), (n *= 10))
580     // E.g.: F("12345678.9") == F(123456789) / 10
581     assert(F("123456789"[0..i] ~ "." ~ "123456789"[i..$]) == F(123456789) / n);
582 
583   assert(F("12345678.9") == F(123456789.0) / 10);
584   assert(F("12345678.9") == F(Format("{}", 12345678.9)));
585   assert(2 / F(0.5) == 4);
586   assert(F(0.5) / 2 == 0.25);
587   assert(F(0.5) * 8 == 4);
588   assert(F(1.2).dup() == F(1.2));
589   assert(F(3.7) < F(3.8));
590   assert(F(99.8) <= F(99.8));
591   assert((F(39) += 61) == F(250e-1) * 4);
592   assert((F(100) /= 5) == (F(50e-1) *= 4));
593   assert((F(111) -= 11) == F(111) - 11);
594   assert(10-F("3.5") == 6.5);
595   assert(10/F("2.5") == 4);
596   assert(F(2401).sqrt() == F(7).pow(2));
597   assert(F(16).neg() == F(-16));
598   assert(F(16).neg().abs() == F(-16).abs());
599   assert(F(1).exp().ln() <= F(1));
600   assert(F(32).square() == F(1024));
601 }
602