String constructor: specify significant figures?


#1

Could we get an additional String constructor to specify the number of significant figures in a float value (as apposed to decimal places).

When using certain values with a large range - such as frequency - it’s nice to be able to keep the displayed values a consistent length (20.000, 200.00, 2000.0, 20000). At the moment I can manage this with a rather ugly if-else block and setting the String’s decimal places based on the value but it would be nice to be able to do this in one line.


#2

#3

This is great, thanks @t0m!


#4

btw, what’s the easiest way to get a String with a fixed number of decimals ?

i.e. to get :

10.     ->  "10.00"
910.0   ->  "910.00"
10.003  ->  "10.00"

#5
String(decimalValue, numDecimalPlaces);

String(10.0, 2) == "10.00";

#6

nope.

DBG (String (10., 2));
DBG (String (910.0, 2));
DBG (String (10.003, 2));

10.0
910.0
10.0

#7

That’s strange, this has always worked for me! :face_with_raised_eyebrow:


#8

perhaps it has changed recently but in the tip the argument is ‘maxNumberOfDecimalPlaces’

/** Creates a string representing this floating-point number.
    @param doubleValue              the value to convert to a string
    @param maxNumberOfDecimalPlaces if this is > 0, it will format the number using no more
                                    decimal places than this amount, and will not use exponent
                                    notation. If 0 or less, it will use a default format, and
                                    exponent notation if necessary.
    @see getFloatValue, getIntValue
*/
String (double doubleValue, int maxNumberOfDecimalPlaces);

#9

Oops, I was looking at master, not develop! You have the most recent version…


#10

Here’s the commit where the change was made…


#11

ah… ok! that’s why I noticed that only recently too!
Perhaps that’s something that should be added to the “breaking change” file?
it won’t “break” things, but it can have a strong impact on the UI (like on the sliders values…).
btw: sorry that I did not start a new thread. It was just supposed to be a side question at first, not a bug report :slight_smile:


#12

I agree, it’s not going to cause any crashes (touches wood) but will likely cause some UI weirdness as you said. To be honest, I’d rather have the old functionality back too!


#13

@t0m, could I propose something like:
(in String::NumberToStringConverters, juce_String.cpp line 499)

static char* doubleToString (char* buffer,
                             int numChars,
                             double n,
                             int numDecPlaces,
                             size_t& len,
                             bool ensureDecimalPlaces = false) noexcept
{
    if (numDecPlaces > 0 && numDecPlaces < 7 && n > -1.0e20 && n < 1.0e20)
    {
        auto* end = buffer + numChars;
        auto* t = end;
        auto v = (int64) (std::pow (10.0, numDecPlaces) * std::abs (n) + 0.5);
        *--t = (char) 0;
        
        if(!ensureDecimalPlaces)
        {
            // skip trailing zeros
            while (numDecPlaces > 1 && (v % 10) == 0)
            {
                v /= 10;
                --numDecPlaces;
            }
        }

        while (v > 0 || numDecPlaces >= 0)
        {
            if (numDecPlaces == 0)
                *--t = '.';

            *--t = (char) ('0' + (v % 10));

            v /= 10;
            --numDecPlaces;
        }

        if (n < 0)
            *--t = '-';

        len = (size_t) (end - t - 1);
        return t;
    }

    StackArrayStream strm (buffer);
    len = strm.writeDouble (n, numDecPlaces);
    jassert (len <= charsNeededForDouble);
    return buffer;
}

Where a bool is used to decide whether or not to stick to the exact number of decimal places are specified or if trailing zeros should be removed.