2017-01-04 5 views
-2

Ich muß mit einer Breite von 20 verdoppelt in C, drucken, aber die maximale Präzision verwenden, dieprintf Doppel mit höchster Präzision in verfügbarer Breite

zum Beispiel in den 20 Zeichen gedruckt werden kann:

-123.123456789123456789 

-123.1234567891234568 

bis jetzt ich den folgenden Code, das funktioniert, ist aber hässlich und hat ein Problem:

sollte gedruckt werden

double num = .......; 
int pr = 0; 
char temp[32] = { 0 }; 
char *point = NULL; 
sprintf(temp, "%.20f", num); 
point = strchr(temp, '.'); 
if (point) { 
    pr = 20 - (1 + point - temp); 
} 
printf("%20.*f", pr, num); 

Das Problem ist, dass dies nicht mit% g statt% f funktioniert, es druckt manchmal mehr als 20 Zeichen, obwohl kein exponentieller Teil existiert. Das Problem tritt auf, wenn eine Zahl wie 0.00angegeben wird. Die zusätzlichen Nullen nach der Dezimalzahl scheinen nicht zu zählen (!).

+1

* "Das Problem ist, dass dies nicht mit% g statt% f funktioniert." * Nicht gut genug. Sei genau. Wie funktioniert es nicht? – user694733

+0

Obwohl OP eines anderen Beitrags nicht für die [Antwort] (http://stackoverflow.com/a/41402788/2410359), das macht, was dieses OP will - denke ich. Das Problem besteht darin, dass es Fälle gibt, in denen die Verwendung eines vorberechneten Formats nicht optimal ist. Die verknüpfte Antwort versucht verschiedene "%. * E" 'Lösungen. – chux

+1

Warum soll die Ausgabe '-123.123456789123456' sein und nicht die genauere' -123.123456789123457'? (Überprüfen Sie die letzte Ziffer) – chux

Antwort

1

Nach ein paar Tipps von chux und answer habe ich die folgende Lösung implementiert, die zu funktionieren scheint. Ich versuche nicht mehr, die richtige Genauigkeit vorher zu berechnen, sondern mit mehr als genug Genauigkeit zu drucken, und später schneide ich die überflüssigen Stellen.

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

static void printDouble(double val, int width) 
{ 
    char *temp = malloc((width + 32) * sizeof(char)); 
    int len = 0; 
    sprintf(temp, "%*.*g", width, width, val); 
    len =strlen(temp); 
    if (len > width) { 
     char *dropped = temp + width; 
     char *last = dropped - 1; 
     char *expon = strchr(temp, 'E'); 
     if (!expon) 
      expon = strchr(temp, 'e'); 
     if (expon) { 
      last = temp + width - 1 - strlen(expon); 
      dropped = last + 1 < expon ? last + 1 : NULL; 
     } 
     if (strchr(temp, '.')) { 
      /* Round */ 
      if (dropped && *dropped >= '5' && *dropped <= '9') { 
       while (*last == '9') 
        last--; 
       (*last)++; 
      } 
      /* Remove trailing zeroes */ 
      while (*last == '0') 
       last--; 
     } 
     if (expon) { 
      while (*expon != '\0') 
       *(++last) = *(expon++); 
     } 
     *(++last) = '\0'; 
    } 
    printf("%*s\n", width, temp); 
    free(temp); 
}