How to convert 7+ digit float/double values to string?



  • I'm trying to make a simple math related program, and I need to be able to support comma numbers. I am using the usual method of converting a float to a string in Qt like this:

    ui->Display->setText(QString::number(floater)); 
    

    And this works pretty fine for small numbers all the way up to 6 digits, at 7 digits (for example 1234567) the string will look something like this:

    1.23457e+06
    

    The problem seems to only apply to the floats converted to string, if I do it the other way around (convert a string to float or double) the result will be just fine.

    How do I fix this? Also how do I make it stop rounding numbers (if an answer to a problem is 12.18, I don't want to see 12.2, if it's 12.98, I don't want to see 13 either, I want to see the precise value after it's converted to the string)



  • @rabcor

    QString::setNum(float n, char format = 'g', int precision = 6)

    allows you to format and set the precision of floats (and similarly for doubles)

    similarly, QString::number(double n, char format = 'g', int precision = 6) allows for setting formatting and precision, if you'd like.



  • I tried the two above, here is an example (with result being the float I want displayed)

    ui->Display->setText(QString::setNum(result, char format = 'g', int precision = 6)); 
    

    I have also tried going the other route (QString::number(double n, char format = 'g', int precision = 6))

    However in both cases the Qt Creator underlines the whole command as red (syntax error I think) and I get the following errors:

    (for setNum/float)

    /home/user/Qt/Open_Anzan/anzan.cpp:50: error: call to non-static member function without an object argument
    ui->Display->setText(QString::setNum(float result, char format = 'g', int precision = 6)); //Placeholder
                         ~~~~~~~~~^~~~~~
    /home/user/Qt/Open_Anzan/anzan.cpp:50: error: expected '(' for function-style cast or type construction
    ui->Display->setText(QString::setNum(float result, char format = 'g', int precision = 6)); //Placeholder
                                         ~~~~~ ^
    /home/user/Qt/Open_Anzan/anzan.cpp:50: error: expected '(' for function-style cast or type construction
    ui->Display->setText(QString::setNum(float result, char format = 'g', int precision = 6)); //Placeholder
                                                       ~~~~ ^
    /home/user/Qt/Open_Anzan/anzan.cpp:50: error: expected '(' for function-style cast or type construction
    ui->Display->setText(QString::setNum(float result, char format = 'g', int precision = 6)); //Placeholder
                                                                          ~~~ ^
    

    (for number/double)

    /home/user/Qt/Open_Anzan/anzan.cpp:50: error: expected '(' for function-style cast or type construction
    ui->Display->setText(QString::number(result, char format = 'g', int precision = 6)); //Placeholder
                                                 ~~~~ ^
    /home/user/Qt/Open_Anzan/anzan.cpp:50: error: expected '(' for function-style cast or type construction
    ui->Display->setText(QString::number(result, char format = 'g', int precision = 6)); //Placeholder
                                                                    ~~~ ^
    

    What am I doing wrong?



  • Hi,
    do it like this:

        const float num = 0.8657876;
        ui->Display->setText( QString().setNum(num, 'g', 4) );
    

    You said:

    I want to see the precise value

    You can't have the precise value because in general the algebraic results of your computations may have infinite numbers of digits and the computer can of course only perform calculations with finite precision due to limited resources in terms of cpu time and memory.



  • @rabcor to follow on from @Wieland :
    In c++, when you see a function listed like:

    void foo(int bar, int baz = 0, string qux = "Default String")
    

    what this means is that there is a function "foo" that takes as parameters an int, an int, and a string, in that order. However, the last two in this example, baz and qux, have default parameters given to them (0 and "Default String") respectively. Since they have default values, you can just leave them out of a function call if you'd like. E.g.:

    foo(5);
    foo(5, 10);
    //foo(5, , "other string"); // I was wrong on this one, see below
    foo(5, 10, "another string);
    

    So in the above functions, what it means is that QString::setNum can easily be called like
    QString::setNum(1.2345) because hidden in that call is the fact that format will be 'g' and precision will be 6, by default. But if you'd like to specify a different format (say, prepending $, or postpending km) or you'd like to specify precision, you can make the same call, but with those values filled out.

    Note, however, that since c++ reads these in order, you can leave out any at the end if you'd like (see the second foo example above)

    Edited: @Chris-Kawa pointed out a mistake in my explanation.


  • Moderators

    The correct solution is close to what @Wieland suggested, but it actually should be corrected to something like this:

    ui->Display->setText(QString::number(floater, 'f', 42)); 
    

    42 is of course whatever precision you need. Be mindful that double type has limited floating point precision.

    The problem with what @Wieland proposed is that it uses the 'g' format, which is the default (selects notation shorter string-length-wise) and is the source of the problem in your case. 'f' always uses the [-]9.9 format, as described here. Also there was a little inefficiency hidden: QString().setNum(num, 'g', 4) - this creates an empty string and then resizes it to the needed length, while the static number() method creates the needed string data once.

    @shavera You can't skip default arguments in the middle, only at the end. foo(5, , "other string"); is a syntax error.



  • Thanks for the help guys, It's working a little bit better now (but it's still not quite working as intended), I just had to do it this way:

    ui->Display->setText(QString::number(result, 'g', 42)); // 42 is the best number!
    

    (e.g. I wasn't supposed to type in "char format = 'f'" or "int precision = 6" rather just write the value I wanted instead.)
    No need to make the float constant either, that would have been messy I think since the float is the most actively changing variable in my code...

    But I am still not in the clear, although they're not as ugly, I am still running into problems when I convert a number with more than 6 digits to a string (or well this time around it happens after 7 digits instead of 6; progress! I can use 1 more digit now (I want a minimum of 15 digits working)).

    For example:
    123456789 is output as -> 123456792
    123.45 is output as -> 123.4499969482421875

    I fail to understand how the former could possibly happen, the second one is a bit more sane (but still not simething I'd want the user to see)

    The only real difference I see between format 'f' and 'g' is that 'g' outputs what I showed above, and 'f' outputs

    123456789 -> 123456792.0000000000000000....
    123.45 -> 123.4499969482421875000000000....

    so format 'f' really doesn't seem to be helping.


  • Moderators

    You misunderstood. 'f' and 'g' are only responsible for the notation e.g.:

    qDebug() << QString::number(0.00001, 'g'); // prints "1e-05"
    qDebug() << QString::number(0.00001, 'f'); // prints "0.000010"
    

    This was the first part.

    The second part is display precision e.g.:

    qDebug() << QString::number(0.12345, 'f', 2); // prints 0.12
    qDebug() << QString::number(0.12345, 'f', 5); // prints 0.12345
    

    So the third param basically says where to 'cut' the number.

    Now the third part is floating point precision, which is separate topic.
    123456789 is output as -> 123456792
    This will not happen with double type, but will happen with float type. This is a loss of precision that is absolutely normal for floating point numbers. I suggest reading the wiki article I linked to earlier. Basically the further from the dot in xxx.yyy you get the bigger the precision loss is e.g. 1.1 is represented ok but 100000000.000000001 will be distorted.



  • @Chris-Kawa thanks for all your help.

    Using a double instead of float I can get good display precision for up to 17 digits (which meets my minimum, but I'd prefer it if I could go even higher), so now this happens:

    12345678901234567 -> 12345678901234568

    As for 'f', the problem I'm having with using 'f' over 'g' is that they handle the given precision number differently, if i put say

      QString::number(12, 'f', 2);
    

    it will be printed as 12.00 (basically it adds zeroes after the dot to fill in every slot that doesn't have a number in it with zero, so if I put precision to 42, I will get 42 zeroes, or 12.000000000000000000000000000000000000000000; if I put 0 precision, then I get flat 12 as I would want. Regardless of what I set the precision to, the main number (before the dot) will always support 17 digits before getting scrambled, but if I don't add numbers after the dot, it adds zeroes for every possible point precision as given by the number (although if I'm reading correctly into these operations, that one will also get scrambled after the 17th digit just like the one before the dot))

    While for 'g', the precision number sets the total amount digits it can represent before getting scrambled, so unlike 'f', if I set the value to 2, it will get scrambled at 123 (on the 3), but just as 'f', if I set it to something high like 42, it will still get scrambled after the 17th digit.

    What I want is to represent numbers that can go from 1 to 999999999999999.99 (minimum, ideally I'd want even higher possible presicion) with the numbers after the dot being limited to two per number (hence the .99) 'f' seems to handle this fairly well if I give it 2 point precision, however the problem there is of course that any integer number will have .00 appended to it, and I do not want that. I want 12 to be read as 12 and not 12.00, while I want 12.2 to still be read as 12.2 or 12.20 (either way is fine since it's the same value, but I definitely would not want it shown as 12.199999999999999 which is what I get if it has higher precision).

    There is some rounding that needs to be done on the numbers during calculations but I think I will handle that separately (so the output to the display would always be a number with a maximum of 2 point numbers to work with)

    Well, if there's any way to use the 'f' with 2 point precision number and prevent the output from printing .00 after every single number that doesn't use points, then I guess my problem would be solved.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.