Different calculation in SQL Server and Excel - sql

This is my formula. I put it in a SQL Server stored procedure:
DECLARE #Var01 float
SET #Var01 = 1164.83 * (1 - 3.3387306 * LOG(0.00459418151829729) + 1.426559 * POWER(LOG(0.00459418151829729),2)) / (1 - 3.4680733 * LOG(0.00459418151829729) + 1.8779192 * POWER(LOG(0.00459418151829729), 2) - 0.21223784 * POWER(LOG(0.00459418151829729), 3) - 0.0035814371 * POWER(LOG(0.00459418151829729), 4) - 0.90903163 * POWER(10, -4) * POWER(LOG(0.00459418151829729), 5)) - 459.67
The result is: 214.630185149416
Then I'm trying to compare to excel, the formula as below:
=1164.83 * (1 - 3.3387306 * LN(0.00459418151829729) + 1.426559 * (LN(0.00459418151829729)) ^ 2) / (1 - 3.4680733 * LN(0.00459418151829729) + 1.8779192 * (LN(0.00459418151829729)) ^ 2 - 0.21223784 * (LN(0.00459418151829729)) ^ 3 - 0.0035814371 * (LN(0.00459418151829729)) ^ 4 - 0.90903163 * 10 ^ -4 * (LN(0.00459418151829729)) ^ 5) - 459.67
The result is: 211.981432072480
The question is, which one is correct? Any Idea? What the calculation is different?

The comments have speculated that this is roundoff error, and that SQL Server is more reliable because it uses more precise floats than Excel. This is wrong. The relative error is about 1%. You do not get relative errors of 1% when you perform a short computation while making roundoff errors of 10-13% unless you are subtracting nearly equal large numbers.
I suggested breaking down the computation to see if SQL Server and Excel agree on the pieces, to see where they diverged. This would have worked. It's like stepping through a program instead of just saying that the end result is not what was desired. You can do a binary search to find the problem rapidly, but the OP didn't provide any additional information.
The computation being performed is
There isn't any cancelation of huge numbers that might cause a large relative error. So, I tried to solve
to see what error in the denominator would result in this miscalculation. With a little calculus, I could check for typos in the constants. The solution is x=-0.410829. That's almost exactly the last term in the denominator. So, the answer isn't that one of these environments produces 1% relative errors in simple floating point calculations, it's that a term was dropped in the denominator. This would have been obvious from breaking the calculation into pieces.
The last term is the only one with something like POWER(10,-4). Could it be that this is carried out using integer arithmetic instead of floating point, so that it evaluates to 0 instead of 0.0001? Yes, apparently that's what SQL Server does. It's like 1/2=0 in integer arithmetic. If you want a decimal output you have to give it a decimal input. Cast the 10 to decimal, change it to POWER(10.0,-4), use 0.0001, or use proper scientific notation for the whole coefficient.

Related

Float precision in Bigquery [duplicate]

We don't have decimal data type in BigQuery now. So I have to use float
But
In Bigquery float division
0.029*50/100=0.014500000000000002
Although
0.021*50/100=0.0105
To round the value up
I have to use round(floatvalue*10000)/10000.
Is this the right way to deal with decimal data type now in BigQuery?
Depends on your coding preferences - for example you can just use simple ROUND(floatvalue, 4)
Depends on how exactly you need to round - up or down - you can respectively adjust expression
For example ROUND(floatvalue + 0.00005, 4)
See all rounding functions for BigQuery Standard SQL at below link
https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-and-operators#rounding-functions
Note that this question deserves a different answer now.
The premise of the question is "We don't have decimal data type in BigQuery now."
But now we do: You can use NUMERIC:
SELECT CAST('0.029' AS NUMERIC)*50/100
# 0.0145
Just make your column is NUMERIC instead of FLOAT64, and you'll get the desired results.
Rounding up in most SQL dialects is not a built-in function unless you're fortunate enough to be rounding up to an integer. In this case, CEIL is a quick and reliable solution.
In the case of rounding decimals up, we can also leverage CEIL, albeit with a couple of additional steps.
The procedure:
Multiply your value to move the last decimal to the tenths position. Ex. 18.234 becomes 1823.4 by multiplying by 100. (n * 100)
Use CEIL() to round up to the nearest integer. In our example, CEIL(n) = 1824.
Divide this result by the same figure used in step 1. In our example, n / 100 = 18.24.
Simplifying these steps leaves us with the below logic:
SELECT CEIL(value * 100) / 100 as rounded_up;
The same logic can be used to round down using the FLOOR function as such:
FLOOR(value * 100) / 100 AS rounded_down;
Thanks to #Mureinik for this answer.

SQL Percent Error. Trouble with trying to use ABS()

I am trying to find the Percent error of two columns for each row.
Currently I tried
UPDATE Weather
SET PercentError=ActualTemp - ForecastTemp / ActualTemp * 100
Which I know is in correct because when i do the calculations it doesn't match up with what the sql gives me. I then tried to use something along the lines of
UPDATE Weather
SET PercentError=ABS (ActualTemp - ForecastTemp) / ActualTemp * 100
But when i do this I just get 0 for my Percent error. I used ABS because I know it works with an INT but wanted to see if it would work when subtracting two columns.
I have been looking up how to subtract two columns using abs but they just use ABS to turn their number into positive and never use it in the equation itself. Is anyone able to point me in the right direction on how to get this to work correctly?
*Using Microsoft sql server
It's doing integer calculations. Try floating point math:
UPDATE Weather
SET PercentError=
(100.0 * ABS (ActualTemp - ForecastTemp)) / ActualTemp
Note that I placed the 100 in front of the equation, and forced the multiplication before the division.
How bout fixing the parentheses?
UPDATE Weather
SET PercentError = (ActualTemp - ForecastTemp) * 100.0 / ActualTemp ;
The 100.0 ensures that the division is not integer division.
Negative numbers seem reasonable, but you can include ABS():
UPDATE Weather
SET PercentError = ABS(ActualTemp - ForecastTemp) * 100.0 / ActualTemp ;

How to use bigquery round up results to 4 digits after decimal point?

We don't have decimal data type in BigQuery now. So I have to use float
But
In Bigquery float division
0.029*50/100=0.014500000000000002
Although
0.021*50/100=0.0105
To round the value up
I have to use round(floatvalue*10000)/10000.
Is this the right way to deal with decimal data type now in BigQuery?
Depends on your coding preferences - for example you can just use simple ROUND(floatvalue, 4)
Depends on how exactly you need to round - up or down - you can respectively adjust expression
For example ROUND(floatvalue + 0.00005, 4)
See all rounding functions for BigQuery Standard SQL at below link
https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-and-operators#rounding-functions
Note that this question deserves a different answer now.
The premise of the question is "We don't have decimal data type in BigQuery now."
But now we do: You can use NUMERIC:
SELECT CAST('0.029' AS NUMERIC)*50/100
# 0.0145
Just make your column is NUMERIC instead of FLOAT64, and you'll get the desired results.
Rounding up in most SQL dialects is not a built-in function unless you're fortunate enough to be rounding up to an integer. In this case, CEIL is a quick and reliable solution.
In the case of rounding decimals up, we can also leverage CEIL, albeit with a couple of additional steps.
The procedure:
Multiply your value to move the last decimal to the tenths position. Ex. 18.234 becomes 1823.4 by multiplying by 100. (n * 100)
Use CEIL() to round up to the nearest integer. In our example, CEIL(n) = 1824.
Divide this result by the same figure used in step 1. In our example, n / 100 = 18.24.
Simplifying these steps leaves us with the below logic:
SELECT CEIL(value * 100) / 100 as rounded_up;
The same logic can be used to round down using the FLOOR function as such:
FLOOR(value * 100) / 100 AS rounded_down;
Thanks to #Mureinik for this answer.

Why is SQL Server changing operation order and boxing the way it does?

Four simple SELECT statements:
SELECT 33883.50 * -1;
SELECT 33883.50 / -1.05;
SELECT 33883.50 * -1 / 1.05;
SELECT (33883.50 * -1) / 1.05;
But the results are not as I would expect:
-33883.50
-32270.000000
-32269.96773000
-32270.000000
That third result is the one that seems questionable. I can see what is happening, first SQL Server evaluates this:
SELECT -1 / 1.05;
Getting an answer of:
-0.952380
Then it takes that answer and uses it to perform this calculation:
SELECT 33883.50 * -0.952380;
To get the (wrong) answer of:
-32269.96773000
But why is it doing this?
In your example
33883.50 * -1 / 1.05
is evaluated as
33883.50 * (-1 / 1.05)
instead of
(33883.50 * -1) / 1.05
which results in a loss in precision.
I played a bit with it. I used SQL Sentry Plan Explorer to see the details of how SQL Server evaluates expressions. For example,
2 * 3 * -4 * 5 * 6
is evaluated as
((2)*(3)) * ( -((4)*(5))*(6))
I'd explain it like this. In T-SQL unary minus is made to be the same priority as subtraction, which is lower than multiplication. Yes,
When two operators in an expression have the same operator precedence
level, they are evaluated left to right based on their position in the
expression.
, but here we have an expression that mixes operators with different priorities and parser follows these priorities to the letter. Multiplication has to go first, so it evaluates 4 * 5 * 6 at first and then applies unary minus to the result.
Normally (say in C++) unary minus has higher priority (like bitwise NOT) and such expressions are parsed and evaluated as expected. They should have made unary minus/plus same highest priority as bitwise NOT in T-SQL, but they didn't and this is the result. So, it is not a bug, but a bad design decision. It is even documented, though quite obscurely.
When you refer to Oracle - that the same example works differently in Oracle than in SQL Server:
Oracle may have different rules for operator precedence than SQL Server. All it takes is to make unary minus highest priority as it should.
Oracle may have different rules for determining result precision and scale when evaluating expressions with decimal type.
Oracle may have different rules for rounding intermediate results. SQL Server "uses rounding when converting a number to a decimal or numeric value with a lower precision and scale".
Oracle may be using completely different types for these kind of expressions, not decimal. In SQL Server "a constant with a decimal point is automatically converted into a numeric data value, using the minimum precision and scale necessary. For example, the constant 12.345 is converted into a numeric value with a precision of 5 and a scale of 3."
Even definition of decimal may be different in Oracle. Even in SQL Server "the default maximum precision of numeric and decimal data types is 38. In earlier versions of SQL Server, the default maximum is 28."
Do you know BODMAS rule. The answer is correct its not because of Sql Server, Its a basic mathematics.
First comes Division then comes the Subtraction, So always Division will happen before Subtraction
If you want to get correct answer then use proper parenthesis
SELECT (33883.50 * -1) / 1.05;
T-SQL has an rule for operator precedence which it follows. You can read about it on the link https://msdn.microsoft.com/en-us/library/ms190276.aspx.
It seems to be a precedence rule concerning unary operators. I have tried the following queries
SELECT 33883.50 * cast(-1 as int) / 1.05;
SELECT 33883.50 * (-1 * 1) / 1.05;
and it returns the right answer. The best thing to do is to use parentheses on expressions you want to occur first, and test thoroughly.

SQL Server POWER function

Using SQL Server 2008 R2 when I enter the following query:
SELECT CAST(POWER(2.0, 63.0) AS BIGINT);
Which yields the result:
9223372036854775800
However, using the Windows desktop calculator and raising 2 to the 63 yields:
9223372036854775807
Can someone please explain the difference -- or is there some internal conversion that SQL Server is doing? ... or am I missing something else?
The range of BIGINTin MS Sql Server is:
-2^63 (-9,223,372,036,854,775,808) to 2^63-1 (9,223,372,036,854,775,807)
And your calculator is giving you the wrong number, because 2^63 can't have an odd number for its right-most digit.
The POWER function in SQL Server (http://technet.microsoft.com/en-us/library/ms174276.aspx), returns the same type as its first argument.
The correct way to write this query is:
DECLARE #foo REAL = 2.0
SELECT CAST(POWER( #foo, 63.0 ) AS BIGINT)
By which, you will get Arithmetic overflow error converting expression to data type bigint. error message.
And about the reason that's
http://www.extremeoptimization.com/resources/Articles/FPDotNetConceptsAndFormats.aspx
And regarding the question of why POWER function is returning a wrong number? As #simonatrcl mentioned in his answer, there is arithmetic problems with floating-point numbers which sometimes result in invalid result. You can read about floating-point numbers and the problems with them here:
http://www.extremeoptimization.com/resources/Articles/FPDotNetConceptsAndFormats.aspx
You can also check the boundaries for integer types in MS Sql Server here:
http://technet.microsoft.com/en-us/library/ms187745.aspx
Power will be returning a FLOAT. Floating point numbers are not accurate beyond certain limits, and will drop a bit of accuracy (if you've ever has a negative 0 problem you'll know what I mean!).
That's what you're getting here...
As far as the calculator goes and tested on XP, Win7 and Win8.1:
2^63 = 9223372036854775808 (obviously)
As far as MSSQL goes:
The upper limit of a BIGINT is defined as 2^63-1, meaning 1 less than 2^63
Now if you would like MSSQL to calculate that for you one would be tempted to write something like:
SELECT POWER(CAST(2 AS BIGINT), 63) - 1
The result would be a bigint because you've cast the first argument of the power to a bigint. MSSQL will first calculate the power and then subtract 1. However, since the result of the power would exceed the range of a bigint, this statement will fail: Arithmetic overflow error converting expression to data type bigint.
So let us invoke some math to solve this. I assume everyone agrees with
2^4 = 2 * 2 * 2 * 2 = 2 * (2^3) = 2^3 + 2^3
and thus
2^4-1 = 2 * 2 * 2 * 2 - 1 = 2 * (2^3) - 1 = 2^3 + 2^3 - 1
That's what we're going to make use of...
SELECT POWER(CAST(2 AS BIGINT), 62) + (POWER(CAST(2 AS BIGINT), 62) - 1)
This results in 9223372036854775807 which is indeed the upper limit of a bigint.
Note that the () around the subtraction is really needed. Otherwise the addition of the result of the two powers would be done first, again resulting in an overflow.