String::toDecimal----Sign-Figures() behaves not as expected

To display 3 decimals in a label I’ve figured out following code:

float cDT1 = 0.f;

label_Delay1->setText(juce::String::toDecimalStringWithSignificantFigures(cDT1, (int)setDecimals(cDT1) + 3), juce::NotificationType(0));

float RootComponent::setDecimals(float Deci)
{
int tInt = (int)Deci;
std::string sDec = std::to_string(tInt);
int sLen = sDec.length();
return sLen;
}

It works fine except when Deci = 10, 100, 1000 etc. Only then 4 decimals are displayed.

I can’t figure out why.

Karel.

I can’t say for certain, but a red flag for me is all the type conversions going on.
In setDecimals you give a float, it is truncated to an int during conversion, then converted to a string, which is measured as an int and returned as a float which is converted to an int.
IMO the return type for setDecimals should really be an int, not a float.

But you probably find that numbers like 99.99999 will be potentially rounded by JUCE to 100, but in your setDecimals it is definitely truncated to 99. This is probably why you’re experiencing the problems at 10, 100, and 1000.

If it were me, I’d be looking into the code of toDecimalStringWithSignificantFigures and finding what conversions and rounding are going on there, then matching them in the setDecimals code.

Thank you for the reply.

The setDecimal function is for getting the length of the number (Deci) without decimals.

So 1234.555 should return 4 which it does. 1000 returns 4 also, so does 2000.

The (int)setDecimals(cDT1) + 3 part sets the number of Significant figures.

In the case of 1000 this is 7. In the case of 2000 this is 7 too.

1000 then is displayed as 1000.0000, 2000 as 2000.000

That’s what I don’t understand.

I use it for the display of the delay length. At 120BPM, 2n = 1000ms.

2n triplet = 666.66667, displayed as 666.667.

As said, every value is displayed correctly except 1000.

It’s not really a big issue but it keeps me debugging, debugging, debugging, …. hahaha. :grinning_face_with_smiling_eyes:

I would still look into the type conversions, truncations, and rounding going on. Floating point numbers don’t always behave the way you would expect them to.

1 Like

If you are unsure on how to use a function, you learn the most about it’s intention in the unit tests:

So you are defining how many significant figures you want to see, and the string length is adapted accordingly.

I don’t understand what you try to achieve with the snippet you posted, maybe you can clarify yout intent.

This piece of code makes me very anxious. Like, what are you trying to achieve here?

Use juce::dontSendNotification instead. Makes it way easier to read.

Wouldn’t that cause the number of sigfigs to be too small, but OP said that 1000 has 1 too many decimal points?

If you just want to get the number of digits before the decimal place, I would change this to:

int RootComponent::getNumDigitsBeforeDecimalPlace(float input)
{
    input = std::abs(input); // If you want to support negative numbers

    if (input < 10.0f)
        return 1;

    return static_cast<int>(std::log10(input)) + 1;
}

The purpose of it all is to always display a three decimal float number in a Label.

To show what I mean I’ve created a new empty juce project and added a label and some code in PluginEditor.h and PluginEditor.cpp

PluginEditor.h (1.1 KB)

PluginEditor.cpp (1.8 KB)

Maybe you could run it with n = 1000 and n = 2000 in the cDT function to see what I mean.

testLabel.setText(juce::String::toDecimalStringWithSignificantFigures(n, 7), juce::dontSendNotification);

With n = 1000 the label shows 1000.0000

With n = 2000 the label shows 2000.000

I used Visual Studio 17.

Thank you very much!. I didn’t know about this one obviously!! I doesn’t solve my issue though.

About the function you tried:

In the source code I quoted (click the link to see more cases) you see on the left the input to the function and what it is expected to produce:

expectEquals (String::toDecimalStringWithSignificantFigures (19368, 1), String ("20000"));

reads as:

test if calling String::toDecimalStringWithSignificantFigures (19368, 1) returns the value after the comma String ("20000")

I am still not sure I understand your use case.

If you want to have three digits after the decimal point use the string constructor:

text = juce::String (number, 3);

Maybe you can give a few examples of numbers and what you want as output, that would help.

Thank you very much Daniel.

The use of the string constructor solved my problem ! ! :slightly_smiling_face: .

All I wanted is a label that displays a float number with 3 decimals

So I tried the code below:

String::toDecimalStringWithSignificantFigures (1000, 7) returns 1000.0000

so that’s 8 figures instead of 7.

while

String::toDecimalStringWithSignificantFigures (2000, 7) returns 2000.000

that’s 7 figures.

I still don’t know why.

Again, thank you!

You’re right it’s a bug I see the issue, I’ll get a fix up for this but if you’re trying to get a specific number of digits after the decimal place as Daniel says the constructor of String is probably the best thing to use.

2 Likes

@pulsepsycle thanks for reporting we pushed a fix for this to develop

1 Like