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?.
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
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.
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.
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
---------------------------
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).
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)
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.
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.
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.
Comments
right := selectstr(2,format(dec)); //right is a text variable
Regards
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.
Epimatic Corp.
http://www.epimatic.com
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
As you can see Left is 12 and right is 345.67 I think that is the wrong answer.
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.
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:
Epimatic Corp.
http://www.epimatic.com
..................................
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);
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)
You gotta be kidding.
is this a competition to see who can do this with the most lines of code?
I am visualizing now a loop, with an embedded case statement, and an array of 100 CHAR.
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.
I tried 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 Shouldn't it?
Once again this thread proves there are many ways to get things done.
Epimatic Corp.
http://www.epimatic.com
When I test with I get That's not correct too.
In some cases you need the exact integer value, so this solution wouldn't help.
Hanen TALBI
If you just need the conversion for sending data (textual)
( Oh and by the way, you may want to create a new thread instead of hijacking someone elses )
So you have to convert the Comma to a '~' for example first
then convert dot to comma, then convert ~ to decimal.
so
1,000.00 would turn to 1.000,00
Independent Consultant/Developer
blog: https://dynamicsuser.net/nav/b/ara3n
How's that?
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.
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.
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.
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.