NumbersSeparator() function for Print big numbers

 

Hi Coders!

I'm looking for a little number to string function.

I have a number, for example: 344256454.23 and I would like to print it in this form: 344,256,454.23

Is it possible with bult-in function? Or I have to write this function?

Thank you.

Relative

 
Compiled, not tested
string DoubleToStrCommaSep(double v, int decimals=4){   // 34,256,454.23
    if (decimals == 0)  return( IntToStrCommaSep(v) );
    if (v < 0)          return( "-" + DoubleToStrCommaSep(-v, decimals) );
    int     integer     = v;
    string  fraction    = StringSubstr(DoubleToStr(v - integer, decimals), 1);
    return( IntToStrCommaSep(integer) + fraction);
}
string IntToStrCommaSep(int integer){
    if (integer < 0)    return( "-" + IntToStrCommaSep(-integer) );
    if (integer < 1000) return(integer);
    string left = IntToStrCommaSep(integer / 1000);
    return( left + "," + RJust(integer % 1000, 3) );
}
string  RJust(string s, int size, string fill="0"){
    while( StringLen(s) < size )    s = fill + s;       return(s);             }
 
string FormatNumber(string numb, string delim=",",string dec=".")
{
int pos=StringFind(numb,dec);
if(pos==-1)
   {
   string nnumb=numb;
   string enumb="";
   }
else
   {
   nnumb=StringSubstr(numb,0,pos);
   enumb=StringSubstr(numb,pos);
   }
int cnt=StringLen(nnumb);
if (cnt<4)return(numb);
int x=MathFloor(cnt/3);
int y=cnt-x*3;
string forma="";
if(y!=0)forma=StringConcatenate(StringSubstr(nnumb,0,y),delim);
for(int i=0;i<x;i++)
   {
   if(i!=x-1)forma=StringConcatenate(forma,StringSubstr(nnumb,y+i*3,3),delim);
   else forma=StringConcatenate(forma,StringSubstr(nnumb,y+i*3,3));
   }
forma=StringConcatenate(forma,enumb); 
return(forma);
}   

Example

int start()
{
Comment(FormatNumber("12345678646372821910.45"));
}
 
Thank you very much WHRoeder and Roger!
 

Roger:
string FormatNumber(string numb, string delim=",",string dec="."){ ... }

Roger, thanks for your code above. It worked perfectly. For some strange reason my text objects that included very large numbers formatted by WHRoeder's code printed blanks but on smaller numbers it worked perfectly also. However, since I want to display very large numbers and text objects along with text I'm running out of space because the number of characters in text objects is limited so my large numbers get cut off.

How can I format the number even more so that millions print as M, billions as B and trillions as T with options to choose which ones I want to format? For example, I may choose to only format billions and trillions but leave the millions unformatted as 1,000,000 OR I may choose to format all three, M, B and T.

I looked at both Roger's and WHRoeder's code but could not figure out how to modify them. I'll really appreciate it if Roger or WHRoeder or anyone else can help with this. I did many google searches but couldn't find the answer to this, neither does Hanover's Handy MQL4 Utility have this feature.

For example:

string FormatNumber(6320000000) should print as 6.32B
Thank you very much coders.
 
string   DoubleToStrCommaSep(double v, int decimals=4, string s=""){ // 6,454.23
   if(decimals == 0) return( IntToStrCommaSep(v,s) );
   int      integer  = v;
   string   fraction = StringSubstr(DoubleToStr(v - integer, decimals), 1);
   return(IntToStrCommaSep(integer,s) + fraction);
}
string   IntToStrCommaSep(int integer, string s=""){
   if(integer < 0){  s="-";   integer = -integer;  }
   for(string right = ""; integer >= 1000; integer /= 1000)
      right = "," + RJust(integer % 1000, 3, "0") + right;
   return(s + integer + right);
}
Must have tested previous because I changed it.
 
WHRoeder:
Must have tested previous because I changed it.


Thanks WHRoeder. However, just after I asked the question I modified your original code and got it to work.

Here is the modified code that works only up to Billions. If you remove the comment // to compile the code for the larger numbers: Septillion: Y; sextillion: Z; Quintillion: E; Quadrillion: and Q; Trillion, and the function tries to return a number larger than billions then the results are crazy but I con't figure out why so I just commented out those larger numbers. I couldn't find anything wrong with my code so maybe the MQL4 language has a limitation.

//---------------------------------------------------------------------------------
// function: DoubleToStrCommaSep()
// Description: Formats numbers with abbreviations & commas to separate thousands
//---------------------------------------------------------------------------------
// Example: DoubleToStrCommaSep(2560000.56,1) returns 2.6M

string DoubleToStrCommaSep(double v, int decimals=4){ // 34,256,454.23
if (v < 0) return( "-" + DoubleToStrCommaSep(-v, decimals) );

string abbr=""
//Septillion: Y; sextillion: Z; Quintillion: E; Quadrillion: Q; Trillion: T; Billion: B; Million: M;
//if (v > 999999999999999999999999) { v = v/1000000000000000000000000; abbr = "Y"; } else
//if (v > 999999999999999999999) { v = v/1000000000000000000000; abbr = "Z"; } else
//if (v > 999999999999999999) { v = v/1000000000000000000; abbr = "E"; } else
//if (v > 999999999999999) { v = v/1000000000000000; abbr = "Q";} else
//if (v > 999999999999) { v = v/1000000000000; abbr = "T";} else
if (v > 999999999) { v = v/1000000000; abbr = "B";} else
if (v > 999999) { v = v/1000000; abbr = "M";}

v = NormalizeDouble(v,decimals);
int integer = v;

if (decimals == 0) {
return( IntToStrCommaSep(integer) + abbr);
}
else {
string fraction = StringSubstr(DoubleToStr(v - integer, decimals), 1);
return( IntToStrCommaSep(integer) + fraction + abbr);
}
}
string IntToStrCommaSep(int integer){
if (integer < 0) return( "-" + IntToStrCommaSep(-integer) );
if (integer < 1000) return(integer);
string left = IntToStrCommaSep(integer / 1000);
return( left + "," + RJust(integer % 1000, 3));
}
string RJust(string s, int size, string fill="0"){
while( StringLen(s) < size ) s = fill + s; return(s);
}
 

Below is my modification of your changed version but this version also only works up to Billions so the same thing applies:

"If you remove the comment // to compile the code for the larger numbers: Septillion: Y; sextillion: Z; Quintillion: E; Quadrillion: and Q; Trillion, and the function tries to return a number larger than billions then the results are crazy but I con't figure out why so I just commented out those larger numbers. I couldn't find anything wrong with my code so maybe the MQL4 language has a limitation."


//---------------------------------------------------------------------------------
// function: DoubleToStrCommaSep()
// Description: Formats numbers with abbreviations & commas to separate thousands
//---------------------------------------------------------------------------------
// Example: DoubleToStrCommaSep(2560000.56,1) returns 2.6M

string DoubleToStrCommaSep(double v, int decimals=4, string s="") { // 6,454.23

string abbr ="";
//Septillion: Y; sextillion: Z; Quintillion: E; Quadrillion: Q; Trillion: T; Billion: B; Million: M;
//if (v > 999999999999999999999999) { v = v/1000000000000000000000000; abbr = "Y"; } else
//if (v > 999999999999999999999) { v = v/1000000000000000000000; abbr = "Z"; } else
//if (v > 999999999999999999) { v = v/1000000000000000000; abbr = "E"; } else
//if (v > 999999999999999) { v = v/1000000000000000; abbr = "Q";} else
//if (v > 999999999999) { v = v/1000000000000; abbr = "T";} else
if (v > 999999999) { v = v/1000000000; abbr = "B";} else
if (v > 999999) { v = v/1000000; abbr = "M";}

v = NormalizeDouble(v,decimals);
int integer = v;

if (decimals == 0) {
return( IntToStrCommaSep(v,s) + abbr);
}
else {
string fraction = StringSubstr(DoubleToStr(v - integer, decimals), 1);
return(IntToStrCommaSep(integer,s) + fraction + abbr);
}
}
string IntToStrCommaSep(int integer, string s=""){
if(integer < 0){ s="-"; integer = -integer; }
for(string right = ""; integer >= 1000; integer /= 1000)
right = "," + RJust(integer % 1000, 3, "0") + right;
return(s + integer + right);
}
string RJust(string s, int size, string fill="0"){
while( StringLen(s) < size ) s = fill + s; return(s);
}
 

Converted whroeder1's code to MQL5.

I noted the max numbers that work for each function in the comments.

Note: I'm actually switching over to nicholishen's code.

// Adapted from: https://www.mql5.com/en/forum/135250
// Max value: 2147483647.9999. . .  , which is the largest integer (see below) plus fraction (.9999 . . . )
string DoubleToStrCommaSep(double number, int decimals=2, string sign="")
{
    if(decimals == 0)
    {
        return( IntToStrCommaSep((int) number, sign) );
    }

    int integer  = (int) number;
    string fraction = StringSubstr(DoubleToString(number - integer, decimals), 1);
    return(IntToStrCommaSep(integer,sign) + fraction);
}
// Max value: 2147483647 = 2^31 - 1 (for 64-bit system)
string IntToStrCommaSep(int integer, string sign="") 
{
    if(integer < 0)
    {  
        sign="-";
        integer = -integer;
    }
    
    string right = "";
    for( ; integer >= 1000; integer /= 1000)
    {
        right = "," + RJust(StringFormat("%d", integer % 1000), 3, "0") + right;
    }

    return(sign + StringFormat("%d", integer) + right);
}
NumbersSeparator() function for Print big numbers
NumbersSeparator() function for Print big numbers
  • 2011.08.19
  • www.mql5.com
Hi Coders! I'm looking for a little number to string function. I have a number, for example: 344256454...
 
 

Late to the party... Here is a template function that can handle whatever number you throw at it. [MQL4/5]

void OnStart()
{
   double num = -134523349345.23452345;
   Print(NumberToString(num,4));
}
//+------------------------------------------------------------------+
#include<Strings\String.mqh>
template<typename T>
string NumberToString(T number,int digits = 0,string sep=",")
{
   CString num_str;
   string prepend = number<0?"-":"";
   number=number<0?-number:number;
   int decimal_index = -1;
   if(typename(number)=="double" || typename(number)=="float")
   {
      num_str.Assign(DoubleToString((double)number,digits));
      decimal_index = num_str.Find(0,".");
   }
   else
      num_str.Assign(string(number));
   int len = (int)num_str.Len();
   decimal_index = decimal_index > 0 ? decimal_index : len; 
   int res = len - (len - decimal_index);
   for(int i = res-3;i>0;i-=3)
      num_str.Insert(i,sep);
   return prepend+num_str.Str();
}