Mirror of :pserver:cvs@cvs.fefe.de:/cvs libowfat https://www.fefe.de/libowfat/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

87 lines
2.0 KiB

  1. #include "fmt.h"
  2. size_t fmt_double(char *dest, double d,int maxlen,int prec) {
  3. union {
  4. double d;
  5. unsigned long long x;
  6. } __u = { .d=d, };
  7. /* step 1: extract sign, mantissa and exponent */
  8. signed int s=__u.x>>63;
  9. signed long e=((__u.x>>52)&((1<<11)-1))-1023;
  10. /* unsigned long long m=*x & ((1ull<<52)-1); */
  11. /* step 2: exponent is base 2, compute exponent for base 10 */
  12. signed long e10=1+(long)(e*0.30102999566398119802); /* log10(2) */
  13. /* step 3: calculate 10^e10 */
  14. int i;
  15. double tmp=10.0;
  16. char *oldbuf=dest;
  17. int initial=1;
  18. int writeok=(dest!=0);
  19. if (s) { d=-d; if (writeok) *dest='-'; --maxlen; dest++; }
  20. if (d==0.0) { if (writeok) *dest='0'; --maxlen; dest++; return dest-oldbuf; }
  21. if ((i=e10)>=0) {
  22. while (i>10) { tmp=tmp*1e10; i-=10; }
  23. while (i>1) { tmp=tmp*10; --i; }
  24. } else {
  25. i=(e10=-e10);
  26. while (i>10) { tmp=tmp*1e-10; i-=10; }
  27. while (i>1) { tmp=tmp/10; --i; }
  28. }
  29. while (d/tmp<1) {
  30. --e10;
  31. tmp/=10.0;
  32. }
  33. /* step 4: see if precision is sufficient to display all digits */
  34. if (e10>prec) {
  35. /* use scientific notation */
  36. int len=fmt_double(writeok?dest:0,d/tmp,maxlen,prec);
  37. if (len==0) return 0;
  38. maxlen-=len; dest+=len;
  39. if (--maxlen>=0) {
  40. if (writeok) *dest='e';
  41. ++dest;
  42. }
  43. for (len=1000; len>0; len/=10) {
  44. if (e10>=len || !initial) {
  45. if (--maxlen>=0) {
  46. if (writeok) *dest=(e10/len)+'0';
  47. ++dest;
  48. }
  49. initial=0;
  50. e10=e10%len;
  51. }
  52. }
  53. if (maxlen>=0) return dest-oldbuf;
  54. return 0;
  55. }
  56. /* step 5: loop through the digits, inserting the decimal point when
  57. * appropriate */
  58. for (; prec>0; ) {
  59. double tmp2=d/tmp;
  60. char c;
  61. d-=((int)tmp2*tmp);
  62. c=((int)tmp2);
  63. if ((!initial)||c) {
  64. if (--maxlen>=0) {
  65. initial=0;
  66. if (writeok) *dest=c+'0';
  67. ++dest;
  68. } else
  69. return 0;
  70. --prec;
  71. }
  72. if (tmp>0.5 && tmp<1.5) {
  73. tmp=1e-1;
  74. initial=0;
  75. if (--maxlen>=0) {
  76. if (writeok) *dest='.';
  77. ++dest;
  78. } else
  79. return 0;
  80. } else
  81. tmp/=10.0;
  82. }
  83. return dest-oldbuf;
  84. }