NumToStr() displays an incorrect number of Decimals [Solved]

Questions about MultiCharts and user contributed studies.
User avatar
JoshM
Posts: 2195
Joined: 20 May 2011
Location: The Netherlands
Has thanked: 1544 times
Been thanked: 1565 times
Contact:

NumToStr() displays an incorrect number of Decimals [Solved]

Postby JoshM » 24 Jun 2011

The number of decimals for a symbol is regulated through the settings in Quote Manager->Edit Symbol->Settings - Price Scale.
I came across this topic when searching for a way to return the number of decimals in a number (for example 5 for 1.56897 and three for 154.025). Below is how I solved this, and perhaps this is of use to someone else.

Code: Select all

if LastBarOnChart_s and barstatus = 2 then begin
value34 = 1 / PriceScale; // returns pricescale with decimals, in this case 0.001
value35 = 0;

while value35 = 0 begin
value40 = value34 * 10; // Multiply by 10 to step-by-step remove the decimals
value50 = value50 + 1; // Counter with number of multiplications
if FracPortion(value40) = 0 then
value35 = 1; // If there aren't any Fractions left; break out the while loop
value34 = value40; // Set value 40 to the new value
end;
Print("The number ", (1/PriceScale):0:4, " has ", value50, " decimals.");
end;
..which returns:

Code: Select all

The number 0.0010 has 3.00 decimals.
Though I am wondering: perhaps there is a more efficient way to do this?

Regards,
Josh
Last edited by JoshM on 09 Sep 2011, edited 1 time in total.

User avatar
TJ
Posts: 7740
Joined: 29 Aug 2006
Location: Global Citizen
Has thanked: 1033 times
Been thanked: 2221 times

Re: How can you remove the 3 decimal places in MC with the E

Postby TJ » 24 Jun 2011

The number of decimals for a symbol is regulated through the settings in Quote Manager->Edit Symbol->Settings - Price Scale.
I came across this topic when searching for a way to return the number of decimals in a number (for example 5 for 1.56897 and three for 154.025). Below is how I solved this, and perhaps this is of use to someone else.

Code: Select all

if LastBarOnChart_s and barstatus = 2 then begin
value34 = 1 / PriceScale; // returns pricescale with decimals, in this case 0.001
value35 = 0;

while value35 = 0 begin
value40 = value34 * 10; // Multiply by 10 to step-by-step remove the decimals
value50 = value50 + 1; // Counter with number of multiplications
if FracPortion(value40) = 0 then
value35 = 1; // If there aren't any Fractions left; break out the while loop
value34 = value40; // Set value 40 to the new value
end;
Print("The number ", (1/PriceScale):0:4, " has ", value50, " decimals.");
end;
..which returns:

Code: Select all

The number 0.0010 has 3.00 decimals.
Though I am wondering: perhaps there is a more efficient way to do this?

Regards,
Josh
you can reduce the calculation to this one line:

Code: Select all


decimal = Log( PriceScale ) / Log(10) ;

User avatar
JoshM
Posts: 2195
Joined: 20 May 2011
Location: The Netherlands
Has thanked: 1544 times
Been thanked: 1565 times
Contact:

Re: How can you remove the 3 decimal places in MC with the E

Postby JoshM » 24 Jun 2011

Thanks TJ! Now that's a reduction! ;)

Have a nice weekend,

Regards,
Josh

User avatar
Stan Bokov
Posts: 963
Joined: 18 Dec 2009
Has thanked: 367 times
Been thanked: 302 times

Re: How can you remove the 3 decimal places in MC with the E

Postby Stan Bokov » 27 Jun 2011

you can reduce the calculation to this one line:

Code: Select all


decimal = Log(PriceScale) / Log(10) ;
Nice... :)

User avatar
JoshM
Posts: 2195
Joined: 20 May 2011
Location: The Netherlands
Has thanked: 1544 times
Been thanked: 1565 times
Contact:

Re: How can you remove the 3 decimal places in MC with the E

Postby JoshM » 08 Sep 2011

you can reduce the calculation to this one line:

Code: Select all


decimal = Log(PriceScale) / Log(10) ;
Hm, if I calculate the decimals and use NumToStr() to print these, I get for certain instruments (for example, USD/JPY) wrong results, even though the formula quoted above does work correctly.

Code:

Code: Select all

variables: numOfDeci(0);

numOfDeci = Log(PriceScale) / Log(10);

if LastBarOnChart_s = true then begin
Print(getsymbolname, " Close: ", NumToStr(Close, 10), " decimals: ", numOfDeci);

Print(Spaces(2), "PriceScale: ", PriceScale);
Print(Spaces(2), "Close with calculated Decimals: ", NumToStr(Close, numOfDeci));
end;
Which gives the following output:

Code: Select all

FGBM Close: 115.9800000000 decimals: 2.00
PriceScale: 100.00
Close with calculated Decimals: 115.98
USD/JPY Close: 78.0290000000 decimals: 3.00
PriceScale: 1000.00
Close with calculated Decimals: 78.03
EUR/USD Close: 1.4475400000 decimals: 5.00
PriceScale: 100000.00
Close with calculated Decimals: 1.44754
As you can see, the number of decimals for the USD/JPY are calculated as 3, yet printed with 2 (output should be 78.029, not 78.03).

What's going wrong here? :)

Regards,
Josh

User avatar
JoshM
Posts: 2195
Joined: 20 May 2011
Location: The Netherlands
Has thanked: 1544 times
Been thanked: 1565 times
Contact:

SOLVED

Postby JoshM » 08 Sep 2011

The only way I can explain this NumToStr() behaviour is saying that it's a 'bug' - which actually means that I'm just out of ways to test/dissect this behaviour. :)
[...]
Anyone got an idea?
Well, it's not a bug and I got it solved (see below), but could have saved a lot of time spent "debugging" this behaviour if I knew that:
  • NumToStr() uses Floor() to determine the number of decimals and not Round().
It's not in the manual or help, but well, at least now we know that. :)

Example:
Code:

Code: Select all

variables: numDeci(0), numDeciToStr(""), myValue(0), remainderStr("");

once cleardebug;

if LastBarOnChart_s = true then begin
value1 = 1.132104982347238974239847692834;
value3 = 10;

while value3 <= 100000000000000000000000 begin

numDeci = Log(value3) / Log(10);

Print("Decimals: ", numDeci, " Floor: ", Floor(numDeci), " NumToStr(): ", NumToStr(value1, numDeci));

// If there's a difference between the values, print these to string with the maximum number of decimals
if numDeci <> Floor(numDeci) then begin

Print(Spaces(3), "Decimals: ", NumToStr(numDeci, 30));
Print(Spaces(3), "Using round in NumToStr(): ", NumToStr(value1, Round(numDeci, 0)));
end;

value3 = value3 * 10;
end;
end;
Which gives the following output:

Code: Select all

Decimals: 1.00 Floor: 1.00 NumToStr(): 1.1
Decimals: 2.00 Floor: 2.00 NumToStr(): 1.13
Decimals: 3.00 Floor: 2.00 NumToStr(): 1.13
Decimals: 2.999999999999999600000000000000
Using round in NumToStr(): 1.132
Decimals: 4.00 Floor: 4.00 NumToStr(): 1.1321
Decimals: 5.00 Floor: 5.00 NumToStr(): 1.13210
Decimals: 6.00 Floor: 5.00 NumToStr(): 1.13210
Decimals: 5.999999999999999100000000000000
Using round in NumToStr(): 1.132105
Decimals: 7.00 Floor: 7.00 NumToStr(): 1.1321050
Decimals: 8.00 Floor: 8.00 NumToStr(): 1.13210498
Decimals: 9.00 Floor: 8.00 NumToStr(): 1.13210498
Decimals: 8.999999999999998200000000000000
Using round in NumToStr(): 1.132104982
Decimals: 10.00 Floor: 10.00 NumToStr(): 1.1321049823
Decimals: 11.00 Floor: 11.00 NumToStr(): 1.13210498235
Decimals: 12.00 Floor: 11.00 NumToStr(): 1.13210498235
Decimals: 11.999999999999998000000000000000
Using round in NumToStr(): 1.132104982347
Decimals: 13.00 Floor: 12.00 NumToStr(): 1.132104982347
Decimals: 12.999999999999998000000000000000
Using round in NumToStr(): 1.1321049823472
Decimals: 14.00 Floor: 14.00 NumToStr(): 1.13210498234724
Decimals: 15.00 Floor: 14.00 NumToStr(): 1.13210498234724
Decimals: 14.999999999999998000000000000000
Using round in NumToStr(): 1.132104982347239
Decimals: 16.00 Floor: 16.00 NumToStr(): 1.1321049823472389
Decimals: 17.00 Floor: 17.00 NumToStr(): 1.13210498234723890
Decimals: 18.00 Floor: 17.00 NumToStr(): 1.13210498234723890
Decimals: 17.999999999999996000000000000000
Using round in NumToStr(): 1.132104982347238900
Decimals: 19.00 Floor: 19.00 NumToStr(): 1.1321049823472389000
Decimals: 20.00 Floor: 20.00 NumToStr(): 1.13210498234723890000
Decimals: 21.00 Floor: 20.00 NumToStr(): 1.13210498234723890000
Decimals: 20.999999999999996000000000000000
Using round in NumToStr(): 1.132104982347238900000
Decimals: 22.00 Floor: 22.00 NumToStr(): 1.1321049823472389000000
Decimals: 23.00 Floor: 22.00 NumToStr(): 1.1321049823472389000000
Decimals: 22.999999999999996000000000000000
Using round in NumToStr(): 1.13210498234723890000000
Solution:
When using calculated values as input for the NumToStr() function, use Round() to ensure that the correct value gets passed, for example:

Code: Select all

NumToStr(1.1255445484, Round(myValue, 0));

Btw, I also noticed that NumToStr() has an limitation of 30 decimals - it does accept higher number of decimals, but the string that subsequently gets generated will only have 30 numbers behind the dot.

Regards,
Josh


Return to “MultiCharts”