• Jeff Moden (8/29/2016)


    Sergiy (8/29/2016)


    Jeff Moden (8/29/2016)


    vdiazh (8/28/2016)


    Is great, thanks

    I hope you're not using the FLOAT version. FLOAT is a binary "approximation" of numbers and it the scale varies according to how many numbers are used to the left of the decimal point, which is a disadvantage in this case.

    There is no better data type for "rate" values than float.

    Any kind of decimal will be less precise than float.

    Someone would have to prove that one to me, Sergiy. I DO understand the benefits of FLOAT for certain things but don't believe that things like amortization tables fit the bill here. Of course, that's based on a previous bad experience and I may have done something incorrectly. Unfortunately, I no loger have the code that cause the "penny skew".

    No-one will prove it to you Jeff, because your instinct is right, and float is not more acurate that all deimal types. Float's best accuracy is 56 bits but decimal (38,19) has more than 100 bits accuracy. But that's not a good reaon for not using floats in some circumstances, where that level of accuracy is not needed (for example in the step from one payment date to the next when computing an amortization table); in fact the reason for not storing the amortization table using float is that float is too accurate and risks gstoring incorrect amounts like 100.0000237 cents when the required value is 100.00 cents, whereas use of (for example) decimal(14,2) avoids that problem. Actually you usually can store the numbers in an amortization table as float if you really want to, but only if you convert them to decimal (to do the required rounding) and then back to float before storing them.

    The values that have to be exact in an amortization table are (i) the mortgage rate quoted (be it annual or monthly or whatever) (ii) the amount payed in at each point, (iii) the initial balance and each balance after applying a payment, (iv) total amount payed (interest plus capital) so far at each point where a balance is calculated, (v) total capital and total interest to be paid at each of those points, and (v) period at which interest compounding occurs. These exact values must be valid values in the currency used (which may preclude the use of decimal - for example amounts in British or Irish currency before Feb 1971 couldn't be expressed in decimal unless it's expressed as a number of pennies rather than as a number of shillings or pounds, which generally wasn't acceptable, but more often enforces the use of decimal - eg current British, Euro, and American currencies). A rate that couldn't be expressed exactly as decimal would be rather unusual - when did you last see a mortgage rate of, for example, three and a third per cent?

    If those values are not expressed exactly, you are doomed to getting wrong results. So don't store the values as float in the table (unless you round them appropriately first) even if you somehow have latest standard floating point (with decimal float instead of binary float - which isn't yet supported in SQL Server, although I hope to see that change before I get too old and gaga to notice).

    All other values should be expressed with the maximum possible precision, but I don't see any reason for those other values ever to be in a table. The step from the end one period to the end of the next should begin by taking the current exact values from the table and converting the values to high precision types. (If you have a badly designed system you also have to convert the rate to a high precision value matching the period's duration - if your compounding interval isn't an exact multiple of the period your payment interval that calculation can be a real pain and and it will be the source of many errors if not sufficiently precise - and calculate the capital base for interest which may not be the same as the total balance in the last row, and not having the declared rate be for an exact multiple of the payment interval is just about guaranteed to produce errors in that.) Then calculate the values for the next row in the table (taking account of most recent interest and the current payment) and converting them all back to the appropriate exact type for storage in the table. You should probably use float for the "high precision" type, not because it's more precise than (for example) decimal(22,10) for typical amounts involved in these calculations (it isn't) but because it costs a lot less CPU power and lower store bus traffic.

    You should not under any circumstances use the power function to calculate for several intervals at once, since doing so implies either using an accurate value at points where the rounded value is required or doing all cacluations at presentation precision, each of which may deliver incorrect results. Use instead the appropriate T-SQL windowed functions or if you are on a pre-ark version of SQL Server use either quirky update (as described by Jeff Moden for running totals) or (:sick:) a while loop to ensure that you compute each row and round its values before using it to compute the next row.

    Tom