Spit a Decimal Value

souravbsouravb Member Posts: 135
Hi,
I have a decimal field amount having value say 35.65.
I want to separate the left and right parts of the decimal and show in different fields. How to do that?.

Comments

  • garakgarak Member Posts: 3,263
    Left := selectstr(1,format(dec)); //Left is a textvariable
    right := selectstr(2,format(dec)); //right is a text variable

    Regards
    Do you make it right, it works too!
  • David_SingletonDavid_Singleton Member Posts: 5,479
    Or if you need as integer then:
    Amount := 35.65;
    IntAmount := amount div 1;
    DecAmount := amount * 100 / mod 100;
    
    David Singleton
  • MalajloMalajlo Member Posts: 294
    evaluate(Left,selectstr(1,format(dec))) ; //Left is a decimal, text, integer, code
    evaluate(right,selectstr(2,format(dec))) ; //right is a decimal, text, integer, code
    
  • jlandeenjlandeen Member Posts: 524
    Hmmm both viable solutions....now I wonder which one would perform better?

    I would think that the pure math operations (i.e. div/mod solution) would perform better as it doesn't need to translate to & from strings which I think should take longer.
    Jeff Landeen - Sr. Consultant
    Epimatic Corp.

    http://www.epimatic.com
  • David_SingletonDavid_Singleton Member Posts: 5,479
    jlandeen wrote:
    Hmmm both viable solutions....now I wonder which one would perform better?

    I would think that the pure math operations (i.e. div/mod solution) would perform better as it doesn't need to translate to & from strings which I think should take longer.

    Although you are correct that it should be faster, that was not my prime concern. But there are more important reasons to consider also.

    Firstly code needs to be readable. There is no need to write complex code that is confusing, KISS. Secondly the code needs to work in all environments. For example try this code
    MyDecimal := 12345.67;
    Left := selectstr(1,format(MyDecimal));
    right := selectstr(2,format(MyDecimal));
    
    message('Left = %1 \ Right = %2',left,right);
    
    ---------------------------
    Microsoft Dynamics NAV
    ---------------------------
     Left = 12
     Right = 345.67
    ---------------------------
    OK   
    ---------------------------
    

    As you can see Left is 12 and right is 345.67 I think that is the wrong answer.
    Amount := 12345.67;
    IntAmount := amount div 1;
    DecAmount := amount * 100 mod 100;
    message('IntAmount = %1 \ DecAmount = %2',intamount,decamount);
    
    ---------------------------
    Microsoft Dynamics NAV
    ---------------------------
    IntAmount = 12345 
     DecAmount = 67
    ---------------------------
    OK   
    ---------------------------
    

    Why the difference?

    Simple the format command is not really designed for manipulating text, it is designed for presenting text. To use the format command in a case like this you need to know the exact conditions, such as the Regional settings of the computer.


    Also the most important issue here (and why I am giving a detailed reply) is that the original post is very badly written. It does not explain WHAT they user is trying to achieve, just HOW they want to do it.

    Is the objective just for formatting on a report, or are the results to be used somewhere else. There may be many better solutions, and maybe none involving manipulation of the source number.

    So posters need to be more clear in what they ask, or they will not get the best solution.
    David Singleton
  • jlandeenjlandeen Member Posts: 524
    You're absolutely right that responses can be much improved if the original question/post is detailed & clear (although I do understand that some users can struggle with English not being their first language).

    Until you're post I didn't see that problem with the selectstr command. It only works if a comma is used as a decimal seperator (there are some locales that do that). So for other locations that use a comma (,) as a thousands separator and a period (.) character as a decimal separator the following code would work - but as pointed out above, the KISS method should be followed and this code is more for discussion/demonstration:
    code:
    MyDecimal := 12345.67;
    TextDecimal := DELCHR(FORMAT(MyDecimal),'=',',');
    DecimalPosition := STRPOS(TextDecimal,'.');
    Left := COPYSTR(TextDecimal,1,DecimalPosition - 1);
    Right := COPYSTR(TextDecimal,DecimalPosition + 1);
    
    MESSAGE('Left = %1\Right = %2',Left,Right);
    
    
    Result:
    ---------------------------
    Microsoft Dynamics NAV
    ---------------------------
    Left = 12345
    
    Right = 67
    ---------------------------
    OK   
    ---------------------------
    
    Jeff Landeen - Sr. Consultant
    Epimatic Corp.

    http://www.epimatic.com
  • navuser1navuser1 Member Posts: 1,329
    Thnx David for your detail reply.
    ..................................

    HI Sourav..try this code...

    MyDec := 11111112.23564

    Pos := STRPOS(FORMAT(MyDec),'.');
    Length := STRLEN(FORMAT(MyDec));

    IntPart :=COPYSTR(FORMAT(MyDec),1,(Pos-1));
    DecPart :=COPYSTR(FORMAT(MyDec),(Pos+1),Length- Pos+1);
    Now or Never
  • jreynoldsjreynolds Member Posts: 175
    If you are going with the FORMAT method why not just use a format string that returns just the integer and decimal portions of the number?
    FORMAT(Amount,0,'<Integer>')
    FORMAT(Amount,0,'<Decimals>')
    
    If you are interested in the math approach keep in mind that the MOD function can be used with decimals and it is not necessary to scale the amount by 100 (or some other power of 10).
    DecAmount := Amount mod 1;
    
  • David_SingletonDavid_Singleton Member Posts: 5,479
    jreynolds wrote:
    If you are interested in the math approach keep in mind that the MOD function can be used with decimals and it is not necessary to scale the amount by 100 (or some other power of 10).
    DecAmount := Amount mod 1;
    

    The " * 100 " was not to scale it, it was to achieve the request of the user, i.e. to split the LEFT and RIGHT parts of the decimal. If you don't multiply by 100 then the RIGHT part will be 0.35 rather than that 35 as requested. 8)
    David Singleton
  • David_SingletonDavid_Singleton Member Posts: 5,479
    navuser1 wrote:
    Thnx David for your detail reply.
    ..................................

    HI Sourav..try this code...

    MyDec := 11111112.23564

    Pos := STRPOS(FORMAT(MyDec),'.');
    Length := STRLEN(FORMAT(MyDec));

    IntPart :=COPYSTR(FORMAT(MyDec),1,(Pos-1));
    DecPart :=COPYSTR(FORMAT(MyDec),(Pos+1),Length- Pos+1);


    You gotta be kidding.

    is this a competition to see who can do this with the most lines of code? :mrgreen:

    I am visualizing now a loop, with an embedded case statement, and an array of 100 CHAR.
    David Singleton
  • David_SingletonDavid_Singleton Member Posts: 5,479
    jreynolds wrote:
    If you are going with the FORMAT method why not just use a format string that returns just the integer and decimal portions of the number?
    FORMAT(Amount,0,'<Integer>')
    FORMAT(Amount,0,'<Decimals>')
    

    I really don't like using FORMAT in situations like this, but IF it had to be using FORMAT, then I agree that this is the better solution.
    David Singleton
  • einsTeIn.NETeinsTeIn.NET Member Posts: 1,050
    Even if you have a comma as delimiter symbol, SELECTSTR also won't work if the integer part and the decimal places part is equal.
    MyDecimal := 67.67;
    Left := selectstr(1,format(MyDecimal));
    Right := selectstr(2,format(MyDecimal));
    
    message('Left = %1 \ Right = %2',left,right);
    

    I tried
    FORMAT(Amount,0,'<Integer>')
    FORMAT(Amount,0,'<Decimals>')
    
    That's a pretty good solution. But I get the delimiter symbol as first sign of "Right". So, I guess it should be something like
    FORMAT(Amount,0,'<Integer>')
    COPYSTR(FORMAT(Amount,0,'<Decimals>'),2)
    
    Shouldn't it?
    "Money is likewise the greatest chance and the greatest scourge of mankind."
  • David_SingletonDavid_Singleton Member Posts: 5,479
    I am just curious, do you programmers get paid by the line? :mrgreen: Why not just use the simplest solution that works? [-o<
    David Singleton
  • einsTeIn.NETeinsTeIn.NET Member Posts: 1,050
    Maybe because
    Amount := 12345.67;
    IntAmount := amount div 1;
    DecAmount := amount * 100 mod 100;
    message('IntAmount = %1 \ DecAmount = %2',intamount,decamount);
    
    will only work if you have exactly 2 decimal places :?: Or I am wrong in my understanding of DIV and MOD...
    "Money is likewise the greatest chance and the greatest scourge of mankind."
  • jlandeenjlandeen Member Posts: 524
    The solution with Mod & Div should work regardless of the number of decimal places. If you needed to only have n significan digits in the decimal place you could simply use the Round function on the decimal value before it's used by mod & div operators.

    Once again this thread proves there are many ways to get things done.
    Jeff Landeen - Sr. Consultant
    Epimatic Corp.

    http://www.epimatic.com
  • einsTeIn.NETeinsTeIn.NET Member Posts: 1,050
    When I test with
    Amount := 12345.6789;
    IntAmount := amount div 1;
    DecAmount := amount * 100 mod 100;
    message('IntAmount = %1 \ DecAmount = %2',intamount,decamount);
    
    I get

    Microsoft Dynamics NAV
    IntAmount = 12.345
    DecAmount = 67,89
    OK
    That's not correct.

    When I test with
    Amount := 12345.6;
    IntAmount := amount div 1;
    DecAmount := amount * 100 mod 100;
    message('IntAmount = %1 \ DecAmount = %2',intamount,decamount);
    
    I get

    Microsoft Dynamics NAV
    IntAmount = 12.345
    DecAmount = 60
    OK
    That's not correct too.
    In some cases you need the exact integer value, so this solution wouldn't help.
    "Money is likewise the greatest chance and the greatest scourge of mankind."
  • HanenHanen Member Posts: 281
    Can you help me please, I need to get my decimal value like this:
    Amount := 12.5;
    
    AmountSent := 12,5;
    
    
    Regards

    Hanen TALBI
  • XypherXypher Member Posts: 297
    Hanen wrote:
    Can you help me please, I need to get my decimal value like this:
    Amount := 12.5;
    
    AmountSent := 12,5;
    
    

    If you just need the conversion for sending data (textual)
    AmountToSend := CONVERTSTR(FORMAT(Amount),'.',',');
    

    ( Oh and by the way, you may want to create a new thread instead of hijacking someone elses )
  • ara3nara3n Member Posts: 9,256
    there is one issue that in thausand are separated by comma.

    So you have to convert the Comma to a '~' for example first
    then convert dot to comma, then convert ~ to decimal.

    AmountToSend := CONVERTSTR(FORMAT(Amount),',','~'); 
    AmountToSend := CONVERTSTR(FORMAT(Amount),'.',','); 
    AmountToSend := CONVERTSTR(FORMAT(Amount),'~','.');
    

    so

    1,000.00 would turn to 1.000,00
    Ahmed Rashed Amini
    Independent Consultant/Developer


    blog: https://dynamicsuser.net/nav/b/ara3n
  • XypherXypher Member Posts: 297
    ara3n wrote:
    there is one issue that in thausand are separated by comma.

    So you have to convert the Comma to a '~' for example first
    then convert dot to comma, then convert ~ to decimal.

    AmountToSend := CONVERTSTR(FORMAT(Amount),',','~'); 
    AmountToSend := CONVERTSTR(FORMAT(Amount),'.',','); 
    AmountToSend := CONVERTSTR(FORMAT(Amount),'~','.');
    

    so

    1,000.00 would turn to 1.000,00

    AmountToSend := CONVERTSTR(FORMAT(Amount,0,'<Integer><Decimals,3>'),'.',',');
    

    How's that? :wink:
  • dorenthasdorenthas Member Posts: 31
    I get

    Microsoft Dynamics NAV
    IntAmount = 12.345
    DecAmount = 67,89
    OK
    That's not correct.

    Looks to me that your locale is set up to use periods as thousand separators and commas as decimal separators. Try including amount in your message output - I'm sure you'll see it displayed as 12.345,6789.
    When I test with
    Amount := 12345.6;
    
    (...)
    I get

    Microsoft Dynamics NAV
    IntAmount = 12.345
    DecAmount = 60
    OK
    That's not correct too.
    In some cases you need the exact integer value, so this solution wouldn't help.

    I agree: if the decimal part has non-significant digits in the precision you want (e.g. 2, in this case), they will become significant digits if multiplied by 10^precision. (0.60 will become 60, rather than 6). Or, if you want all the digits, and not just 2, then if course it doesn't work.

    For either, one solution would be to multiply the decimals by 10 until you reach the end of the decimal string.
    amount := -12345.6789;
    IntAmount := amount div 1;
    DecAmount := ABS(amount - IntAmount);
    WHILE (DecAmount <> DecAmount div 1) DO
      DecAmount := DecAmount * 10; // Thankfully (with SQL Server at least), the Decimal type has a fixed-point precision, so it will always end eventually
    DecAmount := DecAmount div 1;
    
    message('IntAmount = %1 \ DecAmount = %2',intamount,decamount);
    

    Microsoft Dynamics NAV
    IntAmount = -12 345
    DecAmount = 6 789
    OK

    Another solution (sorry David ;)) would be to use the FORMAT function on the decimal part in a manner that is controlled and makes it locale-independant.
    amount := -12345.6789;
    IntAmount := amount div 1;
    IF (amount <> IntAmount)  THEN
      EVALUATE(DecAmount, COPYSTR(FORMAT(ABS(amount - IntAmount)), 3)); // Skip first 2 characters (should be "0," or "0.")
    
    message('IntAmount = %1 \ DecAmount = %2',intamount,decamount);
    

    Still not "one-line-elegant", but this operation probably cannot be carried out with code that is much smaller than the above yet remain fully portable, readable and efficient all at the same time. ("Pretty, good, cheap: choose two.")

    Both solutions above work with negatives as well. And they could easily be modified to add an arbitrary Precision.
Sign In or Register to comment.