Round number up until it is evenly divisible into another number - not limited to integers - sql

As an example I have two numbers (40.25 & 1.88001). In reality the two numbers could be any number with up to five decimal places. However, the second number will always be <= the first number.
I need to round 1.88001 up until it is evenly divisible into 40.25. I need to find a factor of 40.25 that is greater than and closest to 1.88001.
I need to maintain the decimal precision if necessary, meaning I can't just round up to the nearest integer unless a whole number is indeed the closest factor.
I have found other solutions/questions that are similar but have found none that are applicable and/or SQL related.
So far I have a brute force solution that is too slow to be of any real use:
Declare #SheetLength as money = 40.25
Declare #PartLength as money = 1.88001
WHILE #SheetLength % #PartLength > 0
BEGIN
#PartLength = #PartLength + .00001
END
Select #PartLength
There must be a faster/more efficient way to do this ...

What do you mean "round up"? The simplest solution is to take the ratio of the two numbers, take the floor, and divide that into the larger number:
select #SheetLength / floor(#SheetLength / #PartLength)
For your example, this gives 1.91666667.

Related

Allocation via SQL - Retaining repeating decimals for the sum()

I am allocating a single unit across multiple rows using a calculation and storing the results into a table. I am then sum() the allocations and the sums are resulting in numbers that are not whole numbers. What is going on is that some of the allocations are ending up as numbers with repeating decimals, and then the sum of those not adding back up to the whole number (ala 1/3 + 1/3 + 1/3 != 1).
I have tried casting the numbers into different formats, however, Athena keep rounding the decimals at some arbitrary precision resulting in the problem.
I would like the sum of the allocations to equal the sum of the original units.
My Database is AWS Athena which I understand to use the Presto SQL language.
Example of my allocation:
case
when count_of_visits = 1 then 1
when count_of_visits = 2 then .5
when count_of_visits >= 3 then
case
when visit_seq_number = min_visit_seq_number then .4
when visit_seq_number = max_visit_seq_number then .4
else .2 / (count_of_visits - 2 )
end
else 0
end as u_shp_alloc_leads
In this allocation, the first and last visits get 40% of the allocation and all visits in between split 20%
A unit that is being allocated to 29 visits ends up dividing the 20% by 27 which equals 0.00740Repeating. The table is storing 0.007407407407407408 which when I go to sum the numbers the result is 1.0000000000000004 I would like the result to be 1
This is a limitation of databases or computers in general. When you work with fractions like that, some sort of rounding will always take place.
I would apply a reasonable degree of rounding to the x-th decimal on the sums you retrieve from your table, that will just cut off these residual decimals at the end.
If that's not sufficient for you, something you can do to at least theoretically have full precision is to store numerator and denominator separately in two columns. When computing sum( numerator_column/denominator_column ) you will see the same rounding effects, so summing up the numbers would be something a little more complicated like this:
SELECT sum(numerator_sum/denominator)
FROM (
SELECT
denominator,
sum(numerator) as numerator_sum
FROM your_allocation_table
GROUP BY denominator
)

What is the difference between MOD and REMAINDER in oracle?

Although both the functions perform the same operation, even they produce same o/p, what is basic difference between these two? Is there any performance related difference, if yes, then which one is better?
Thanks
The documentation is pretty clear on the difference:
NOTE
The REMAINDER function uses the round function in its formula, whereas
the MOD function uses the floor function in its formula.
In other words, when the arguments are positive integers, the mod function returns a positive number between 0 and the second argument. The remainder function returns a number whose absolute value is less than the second argument divided by 2.
The differences can be more striking for negative numbers. One example of a difference is:
REMAINDER(-15, 4)
MOD(-15, 4)
The first gives -3 and the second 1.
EDIT:
What is happening here? How many times does 4 go into -15. One method is "-4" times with a remained of 1. That is: -15 = 4*(-4) + 1. The other is "-3" times: -15 = 4*(-3) - 3.
The difference what is -15/4 expressed as an integer. Using floor, you get -4. Using round, you get -3.
The difference between MOD and REMAINDER function can be understood in the example below:
MOD(13,5): returns 3 whereas, REMAINDER (13,5) returns -2
A simple way to understand the difference is that MOD uses the floor function therefore it counts the occurrence of the second number within the first and returns what is left to complete the first number i.e. 2(5) gives 10 adding 3 gives 13 therefore MOD(13,5)=3
However, the REMAINDER uses a Round function it therefore gets the total number of the second number that could make up the first and then subtract the what makes it excess. i.e. 3(5) = 15 and subtracting 2 gives 13,therefore REMAINDER(13,5)= -2
REMAINDER (-15, 4): 4(-4) gives -16 and adding +1 gives -15 hence REMAINDER (-15,4)=+1
MOD (-15, 4): 3(-4) gives -12, adding -3 gives us -15 hence MOD(15,4)=-3
REMAINDER(-15, 4)--uses round without taking the sign of the number into
consideration.
hence -15/4= -3.75==> round(-3.75)= -4.--(ignore sign during round)
-4*4= -16
-15-(-16)=>1
There fore: REMAINDER(-15, 4)=1
MOD(-15, 4)----uses Floor without taking the sign of the number into
consideration.
-15/4= -3.75==> floor(-3.75)= -3.--(ignore sign in floor)
-3*4=-12
-15-(-12)=>-3
There fore: MOD(-15, 4)= -3
Mod(m,n) is so simple to understand.
Finding Value Mod() output value will always be the manually calculated remainder value when we divide m by n.
Finding Sign The sign of the output remains the same as the first parameter.
eg :
eg 1 : mod (11,3) is the remainder of 11/3 which is 2 and the same sign of 1st parameter. So output is 2
eg 2 : mod (-11,3) is the remainder of 11/3 which is 2 and the same sign of the 1st parameter. So the output is -2
Remainder(m,n) is a bit different
Finding Value You take two multiples of n, such that when multiplied gives the closest lower value and the closest upper value compared to the first parameter(m). The minimum difference between these values will be the output value
Finding Sign The sign of the output value will always be positive if the closest value is less than the first parameter and the if the closest value is greater than the 1st parameter then it will be negative.
eg :
eg 1 : remainder(10,3) The closest multiple values of 3 which are lesser and greater than 10 are 9(3x3) and 12(3x4). And the closest to 10 among 9 & 12 is 9. So the output will be the gap between 9 and 10 which is 1. The closest number is less than the 1st parameter. So the output is 1.
eg 2 : remainder(11,3) The closest multiple values of 11 which are lesser and greater than 11 are 9(3x3) and 12(3x4). And the closest to 12 among 9 & 12 is 12. So the output will be the gap between 12 and 11 which is 1. The closest number is greater than the 1st parameter. So the output is -1.
The question has long had an answer, but I thought some context would be helpful.
https://en.wikipedia.org/wiki/Modulo_operation discusses the “modulo” operation, and the fact that it is based on the remainder after integer division. The problem is that the concept of “remainder” is not clearly defined where there are negative numbers.
Where negative numbers are involved, the difference between modulus and remainder is significant. Mathematically, the modulus operation maps an integer on to a range. This range begins at 0 and is cyclic. For example integer mod 3 is mapped on to the range:
0, 1, 2, 0, 1, 2, …
If the given integer is negative, the cycle is simply extended backwards. If, however, the modulus itself is negative, then the whole range is negative:
0, -2, -1, 0, -2, -1, …
https://rob.conery.io/2018/08/21/mod-and-remainder-are-not-the-same/ illustrates this as a clock with negative numbers.
The practical upshot of this is that the sign of the second number is the same as the sign of the result.
With a remainder, however, you attempt to divide the second number into the first number until you can’t go any more. The remaining difference is called the remainder. If the first number is negative, then, if you stop short, the remainder will be negative.
The practical upshot of which is that the sign of the first number is the sign of the result.
Most coding languages, including most variations of SQL, use a remainder calculation, but very often call it the modulus. And most languages use the notation a % b meaning a mod b.
Oracle, of course, has two functions, which should have been helpful. However, the first function, mod(), actually gives what everybody else calls the remainder. The second, remainder() gives a result which nobody else gives, due to the fact that it is focused on the nearest division. As per the documentation, the mod() functions uses the floor() function, while remainder() uses round().
If you want to compare the results, you can try:
SELECT
remainder(19,5) AS "Remainder ++",
remainder(-19,5) AS "Remainder -+",
remainder(19,-5) AS "Remainder +-",
remainder(-19,-5) AS "Remainder --",
mod(19,5) AS "Mod ++",
mod(-19,5) AS "Mod -+",
mod(19,-5) AS "Mod +-",
mod(-19,-5) AS "Mod --",
mod(mod(19,5) + 5,5) AS "Modulo ++",
mod(mod(-19,5) + 5,5) AS "Modulo ++",
mod(mod(19,-5) + -5,-5) AS "Modulo ++",
mod(mod(-19,-5) + -5,-5) AS "Modulo ++"
FROM DUAL
;
The modulo calculation gives the true modulus, according to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Remainder
In all, you probably want the remainder as the most natural interpretation, and so you will use mod() to get this result.

Error taking int of logs in VBA

When I calculate log(8) / log(2) I get 3 as one would expect:
?log(8)/log(2)
3
However, if I take the int of this calculation like this the result is 2 and thus wrong:
?int(log(8)/log(2))
2
How and why does this happen?
Likely because the actual number returned is of type double. Because floats and doubles cannot accurately represent most base 10 rational numbers the number returned is something like 2.99999999999. Then when you apply int() the .999999999 is truncated.
How floating-point number works: it dedicates a bit for the sign, a few bits to store an exponent, and the rest for the actual fraction. This leads to numbers being represented in a form similar to 1.45 * 10^4; except that instead of the base being 10, it's two.

How do you multiply two fixed point numbers?

I am currently trying to figure out how to multiply two numbers in fixed point representation.
Say my number representation is as follows:
[SIGN][2^0].[2^-1][2^-2]..[2^-14]
In my case, the number 10.01000000000000 = -0.25.
How would I for example do 0.25x0.25 or -0.25x0.25 etc?
Hope you can help!
You should use 2's complement representation instead of a seperate sign bit. It's much easier to do maths on that, no special handling is required. The range is also improved because there's no wasted bit pattern for negative 0. To multiply, just do as normal fixed-point multiplication. The normal Q2.14 format will store value x/214 for the bit pattern of x, therefore if we have A and B then
So you just need to multiply A and B directly then divide the product by 214 to get the result back into the form x/214 like this
AxB = ((int32_t)A*B) >> 14;
A rounding step is needed to get the nearest value. You can find the way to do it in Q number format#Math operations. The simplest way to round to nearest is just add back the bit that was last shifted out (i.e. the first fractional bit) like this
AxB = (int32_t)A*B;
AxB = (AxB >> 14) + ((AxB >> 13) & 1);
You might also want to read these
Fixed-point arithmetic.
Emulated Fixed Point Division/Multiplication
Fixed point math in c#?
With 2 bits you can represent the integer range of [-2, 1]. So using Q2.14 format, -0.25 would be stored as 11.11000000000000. Using 1 sign bit you can only represent -1, 0, 1, and it makes calculations more complex because you need to split the sign bit then combine it back at the end.
Multiply into a larger sized variable, and then right shift by the number of bits of fixed point precision.
Here's a simple example in C:
int a = 0.25 * (1 << 16);
int b = -0.25 * (1 << 16);
int c = (a * b) >> 16;
printf("%.2f * %.2f = %.2f\n", a / 65536.0, b / 65536.0 , c / 65536.0);
You basically multiply everything by a constant to bring the fractional parts up into the integer range, then multiply the two factors, then (optionally) divide by one of the constants to return the product to the standard range for use in future calculations. It's like multiplying prices expressed in fractional dollars by 100 and then working in cents (i.e. $1.95 * 100 cents/dollar = 195 cents).
Be careful not to overflow the range of the variable you are multiplying into. Your constant might need to be smaller to avoid overflow, like using 1 << 8 instead of 1 << 16 in the example above.

Why decimal behave differently?

I am doing this small exercise.
declare #No decimal(38,5);
set #No=12345678910111213.14151;
select #No*1000/1000,#No/1000*1000,#No;
Results are:
12345678910111213.141510
12345678910111213.141000
12345678910111213.14151
Why are the results of first 2 selects different when mathematically it should be same?
it is not going to do algebra to convert 1000/1000 to 1. it is going to actually follow the order of operations and do each step.
#No*1000/1000
yields: #No*1000 = 12345678910111213141.51000
then /1000= 12345678910111213.141510
and
#No/1000*1000
yields: #No/1000 = 12345678910111.213141
then *1000= 12345678910111213.141000
by dividing first you lose decimal digits.
because of rounding, the second sql first divides by 1000 which is 12345678910111.21314151, but your decimal is only 38,5, so you lose the last three decimal points.
because when you divide first you get:
12345678910111.21314151
then only six decimal digits are left after point:
12345678910111.213141
then *1000
12345678910111213.141
because the intermediary type is the same as the argument's - in this case decimal(38,5). so dividing first gives you a loss of precision that's reflected in the truncated answer. multiplying by 1000 first doesn't give any loss of precision because that doesn't overload 38 digits.
It's probably because you lose part of data making division first. Notice that #No has 5-point decimal precision so when you divide this number by 1000 you suddenly need 8 digits for decimal part:
123.12345 / 1000 = 0.12312345
So the value has to be rounded (0.12312) and then this value is multiply by 1000 -> 123.12 (you lose 0.00345.
I think that's why the result is what it is...
The first does #No*1000 then divides it by 1000. The intermediates values are always able to represent all the decimal places. The second expression first divides by 1000, which throws away the last two decimal places, before multiplying back to the original value.
You can get around the problem by using CONVERT or CAST on the first value in your expression to increase the number of decimal places and avoid a loss of precision.
DECLARE #num decimal(38,5)
SET #num = 12345678910111213.14151
SELECT CAST(#num AS decimal(38,8)) / 1000 * 1000