Decimal numbers are being rounded off after performing arithmetic operations - abap

I'm trying to make a simple ABAP program that exercises various arithmetic operations.
The first number is: 5
The second number is 3
Answers should be:
SUM: 8
DIFFERENCE: 2
PRODUCT: 15
QUOTIENT: 1.67
MODULO: 2
I tried declaring the quotient variable into Packed Number and include 2 decimal places but I'm getting different results.
Here's my code:
*Parameter declaration - Display fields
PARAMETERS: p_no1 TYPE p DEFAULT 5,
p_no2 TYPE p DEFAULT 3.
*Data Declaration
DATA(gv_sum) = ( p_no1 + p_no2 ).
DATA(gv_diff) = ( p_no1 - p_no2 ).
DATA(gv_prod) = ( p_no1 * p_no2 ).
DATA: gv_quo TYPE p DECIMALS 2,
gv_mod TYPE p DECIMALS 2.
gv_quo = ( p_no1 DIV p_no2 ).
gv_mod = ( p_no1 MOD p_no2 ).
*Output
WRITE: 'First Number is:', p_no1,
/ 'Second Number is:', p_no2,
/ 'The Sum is:', gv_sum,
/ 'The Difference is:', gv_diff,
/ 'The Product is:', gv_prod,
/ 'The Quotient is:', gv_quo,
/ 'The Modulo is:', gv_mod.
The result I'm getting:

DIV gives you the rounded result of your division.
If you wants the decimal part go for '/' instead of DIV.
MOD gives you remainder of your division.
Best regards
Sebastian

Related

How to convert number (price) in to multiples of 0.05 using AutoHotKey script?

I was automating a trading software using AHK script. During price submission the app does not accept in between values, say between 1.50 and 1.55. It only accepts multiples of 0.05 because its tick-size is 0.05 hence i have to do the price conversion using AHK script.
You can just use
Round(N / 0.05) * 0.05
Example
Round(1.53 / 0.05) * 0.05 ; Returns 1.55
Explanation
I'm going to explain with 0.01 because it's easier to visualize, but it applies to any number. The number to round is 1.234. Anything after 3 will need to be discarded in the rounding process.
If we divide the number 1.234 by 100, we get 123.4. Note how the period is after 3. So we can just use Round now.
After rounding, the number is 123. Now we just need to scale it back down by multiplying by 0.01, which results in 1.23.
Formatting
As 0x464e pointed out in the comments, due how floating-point numbers work, the result may be imprecise. So if you're going to convert them to strings, do so using Format("{:.2f}", number).
The 2 comes from the minimum number of decimal places needed to accurately represent any number multiple of 0.05. By the way, this can be calculated by using:
Ceil(Log(1 / 0.05)) ; Returns 2
The following AHK function Roundoff converts and returns the price in its nearest tick-size multiple.
Roundoff(price) ;round off to nearest 5 paisa value
{
price := Round(price, 2) ;ronded to 2 decimal places
priceNoDecimal := Floor(price)
decimalPart := price - priceNoDecimal
decimalPart := Floor( Round(decimalPart * 100, 2) )
numerator := Floor(decimalPart / 5)
remainder := Mod(decimalPart, 5)
if ( remainder > 2)
retval := (numerator * 5) + 5
if ( remainder < 3)
retval := (numerator * 5)
retval := Round(priceNoDecimal + (retval / 100), 2)
return retval
}

Type of inline declaration with calculation

I am declaring a variable with inline declaration 50 * ( 2 / 5 ). The problem is that output result is 0 instead of expected 20.
DATA(exact_result) = 50 * ( 2 / 5 ) .
cl_demo_output=>display( exact_result ).
Can anyone suggest why the result is zero where as 50 * (2/5) = 20.
regards,
Umar Abdullah
The inline declaration assigns a data type depending on the type from the Right-Hand Side (RHS) expression. With an arithmetic expression, the compiler determines a data type based on the overall calculation type.
First, 2 and 5 are considered as type I (4 bytes integer), so the result is also of type I even if the operator is a division (integer division in that precise case).
Then, 50 is also considered as type I, and because it's used with another I-type data object (result of subexpression 2 / 5 which is of type I) the result is also of type I.
So, in your example, EXACT_RESULT is assigned the type I.
At run time, because both LHS and RHS data objects are of type I, then the calculation type is I too. Consequently, 2 / 5 equals 0.4 which is rounded to 0 because it's an integer division and the default ABAP rounding is "half up" (rounding of 0.4 gives 0, but 0.5 gives 1).
The workaround is to define explicitly the data type of EXACT_RESULT as having digits after the decimal point (DECFLOAT16, DECFLOAT34, P type with decimals, F and even C because then the calculation type is P !), because the type of the LHS will have a higher priority than the type of the RHS (I), so the calculation will be deduced from the type of the LHS variable.
DATA(exact_result) = CONV decfloat16( 50 * ( 2 / 5 ) ).
Be careful with this next solution : as I said, C leads to a calculation with type P and many decimals, so we could think this example is a good solution :
DATA(exact_result) = '50' * ( 2 / 5 ). " equals 20
But with inline declarations, a P calculation type leads to a data object of type P but with 0 digits after the decimal point, so the result is truncated with other numbers (8 instead of 50 here) :
DATA(exact_result) = '8' * ( 2 / 5 ). " rounded ! (3 instead of 3.2)

SQL server round down wit 0.5 step [duplicate]

I read all rounding functions of T-SQL like Round, Floor, and Ceil, but none of them has rounded down decimal numbers correctly for me.
I have 2 questions:
How to round down a decimal number (3.69 ==> 3.5)?
How to round up the last 3 digits of an integer (e.g. 142600 ==> 143000)?
1) select CAST(FLOOR(2 * 3.69) / 2 AS decimal(2, 1)) handles the first case - courtesy of an answer to a similar question on SQL Server Forums, which I adapted and quickly checked.
Note that if the numbers you are rounding to the nearest 0.5 could be bigger (e.g. 333.69 => 333.5), be sure to specify more decimal precision when you cast (e.g. select CAST(FLOOR(2 * 3.69) / 2 AS decimal(10, 1))), or you could get an overflow error:
Msg 8115, Level 16, State 8, Line 1
Arithmetic overflow error converting numeric to data type numeric.
Extra precision will not affect the bottom-line result (i.e. select CAST(FLOOR(2 * 3.69) / 2 AS decimal(10, 1)) and select CAST(FLOOR(2 * 3.69) / 2 AS decimal(2, 1)) both yield 3.5); but it is wasteful if the numbers you are rounding will always be smaller.
Online references with examples are available for T-SQL FLOOR, CAST, and decimal to help.
2) select ROUND(142600, -3) handles the second case.
A similar online reference is available for T-SQL ROUND.
As per #J0e3gan 's anwser, Sql Server's Round allows rounding to the nearest powers of 10 using the length parameter, where length is 10^(-length), e.g.
length = 0 : 10 ^ 0 = nearest 1
length = 3 : 10 ^ -3 = nearest .001
length = -3 : 10 ^ 3 = nearest 1000
etc
However, in general, with a simple 1-based rounding function - e.g. (Sql Round with Length=0) to round to an arbitrary value of "nearest N" - with the formula:
round(X / N) * N
e.g. nearest 100
select round(12345 / 100.0, 0) * 100.0 -- 12300
select round(-9876 / 100.0, 0) * 100.0 -- -9900
select round(-9849 / 100.0, 0) * 100.0 -- -9800
... Nearest 0.5
select round(5.123 / 0.5, 0) * 0.5 -- 5.000
select round(6.499 / 0.5, 0) * 0.5 -- 6.500
select round(-4.499 / 0.5, 0) * 0.5 -- -4.50
... Nearest 0.02
select round(5.123 / .02, 0) * .02 -- 5.12
select round(-9.871 / .02, 0) * .02 -- -9.88
etc
Remember that the type used for the divisors must be numeric / decimal or float.
The Oracle/PLSQL FLOOR function returns the largest integer value that is equal to or less than a number.
eg:
FLOOR(7.9)
Result: 7
FLOOR(30.29)
Result: 30
FLOOR(-7.9)
Result: -8

spliting a decimal values to lower decimal in sql server

How can i split a decimal value into two decimal values.
if the decimal number which has fractional part that is less than .50 or greater than .50 .it should split in such a way that first no should end with only .00 or .50. second value should contain the remaining factorial value.
ex. 19.97 should return 19.50 & 0.47
19.47 19.00 & 0.47
You can "floor" to the highest multiple of 0.5 by multiplying by 2, calling FLOOR, then dividing by 2. From there just subtract that from the original value to get the remainder.
DECLARE #test decimal(10,7)
SELECT #test =19.97
SELECT
FLOOR(#test * 2) / 2 AS base,
#test - FLOOR(#test * 2) / 2 AS fraction
or to reduce duplication
SELECT
base,
#test - base AS fraction
FROM ( SELECT FLOOR(#test * 2) / 2 AS base )
Declare #money money
Set #money = 19.97
Select convert(int,#money - (#money % 1)) as 'LeftPortion'
,convert(int, (#money % 1) * 100) as 'RightPortion'
Observe that doubling 0.5 gives 1, which is a whole number. This leads to a simple algorithm:
Double the number
Split it into a whole and a fractional parts by using floor(x) and x-floor(x)
Divide each part separately by 2 to give you the results that you need.
Let's take your numbers as an example:
19.97 * 2 = 39.94
Whole part = 39, fractional part = 0.94
Dividing each part by 2 individually, we get
39/2 = 19.50
0.94/2 = 0.47
19.47 * 2 = 38.94
Whole part = 38, fractional part = 0.94
Dividing each part by 2 individually, we get
38/2 = 19.00
0.94/2 = 0.47
You would need to look into the MODULO operator in SQL Server.
SELECT
19.97 as myDecVal ,
19.97 % 0.5 AS decGreaterThan50,/*should return 0.47*/
19.97- (19.97 % 0.5) as roundedToNearestZeroPoint5 /*should return 19.50*/;

SQL Round Function

round(45.923,-1) gives a result of 50. Why is this? How it is calculated?
(sorry guys i was mistaken with earlier version of this question suggesting value was 46)
The SQL ROUND() function rounds a number to a precision...
For example:
round(45.65, 1) gives result = 45.7
round(45.65, -1) gives result = 50
because the precision in this case is calculated from the decimal point. If positive then it'll consider the right side number and round it upwards if it's >= 5, and if <=4 then round is downwards... and similarly if it's negative then the precision is calculated for the left hand side of decimal point... if it's >= 5
for example round(44.65, -1) gives 40
but round(45.65, -1) gives 50...
ROUND(748.58, -1) 750.00
the second parameter: Lenght, is the precision to which numeric_expression is to be rounded. length must be an expression of type tinyint, smallint, or int. When length is a positive number, numeric_expression is rounded to the number of decimal positions specified by length. When length is a negative number, numeric_expression is rounded on the left side of the decimal point, as specified by length.
From
It is expected to be 50.
round(45.923, 0) => 46
expl: the last non-decimal digit is rounded (5), the desicion is based on the next digit (9)
9 is in the high half, ergo 5 is rounded up to 6
round(45.923, 1) => 45.9
expl: the first decimal digit is rounded (9), the desicion is based on the next digit (2)
2 is in the low half, ergo 9 stays 9
your case:
round(45.923, 1-) => 45.92
expl: the secon-last non-decimal digit is rounded (4), the desicion is based on the next digit (5)
5 is in the top half, ergo 4 is rounded up to 5, the rest of the digist are filled with 0s
As for how, start by considering how you'd round a (positive) float to the nearest integer. Casting a float to an int truncates it. Adding 0.5 to a (positive) float will increment the integer portion precisely when we want to round up (when the decimal portion >= 0.5). This gives the following:
double round(double x) {
return (long long)(x + 0.5);
}
To add support for the precision parameter, note that (for e.g. round(123456.789, -3)) adding 500 and truncating in the thousands place is essentially the same as adding 0.5 and to rounding to the nearest integer, it's just that the decimal point is in a different position. To move the radix point around, we need left and right shift operations, which are equivalent to multiplying by the base raised to the shift amount. That is, 0x1234 >> 3 is the same as 0x1234 / 2**3 and 0x1234 * 2**-3 in base 2. In base 10:
123456.789 >> 3 == 123456.789 / 10**3 == 123456.789 * 10**-3 == 123.456789
For round(123456.789, -3), this means we can do the above multiplication to move the decimal point, add 0.5, truncate, then perform the opposite multiplication to move the decimal point back.
double round(double x, double p) {
return ((long long)((x * pow10(p))) + 0.5) * pow10(-p);
}
Rounding by adding 0.5 and truncating works fine for non-negative numbers, but it rounds the wrong way for negative numbers. There are a few solutions. If you have an efficient sign() function (which returns -1, 0 or 1, depending on whether a number is <0, ==0 or >0, respectively), you can:
double round(double x, double p) {
return ((long long)((x * pow10(p))) + sign(x) * 0.5) * pow10(-p);
}
If not, there's:
double round(double x, double p) {
if (x<0)
return - round(-x, p);
return ((long long)((x * pow10(p))) + 0.5) * pow10(-p);
}
It doesn't for me on MySQL:
mysql> select round(45.923,-1);
+------------------+
| round(45.923,-1) |
+------------------+
| 50 |
+------------------+
1 row in set (0.00 sec)
And on Sql Server 2005:
select round(45.923,-1)
------
50.000
What database are you running this on?
one thing is in the round function first parameter is the number and the second parameter is the precision index from the decimal side.
That means if precision index is 0 it is at the first decimal, -1 means before the decimal first number, 1 means right side of the first decimal i.e second decimal
For example
round(111.21,0)---------> return 111
round(115.21,-1)--------->return 120
round(111.325,2)---------->return 111.33
round(111.634,1)-----------> return 111.6