Расхождение в расчетах

SET QUOTED_IDENTIFIER ON
GO

ALTER FUNCTION [dbo].[fn_LensThickCalcAC] (@sph as DECIMAL(9,2),
                              @cyl as DECIMAL(9,2),
                              @ri as DECIMAL(9,2),
                              @bc as DECIMAL(9,2), 
                              @dia as SMALLINT,
                              @ct as DECIMAL(9,2),
                              @axs as SMALLINT)
RETURNS FLOAT
AS 
BEGIN 

DECLARE @dR2S DECIMAL(9,2)
DECLARE @dR2SC DECIMAL(9,2)
DECLARE @dSizeA DECIMAL(9,2)
DECLARE @dSizeB DECIMAL(9,2)
DECLARE @dSizeC DECIMAL(9,2)
DECLARE @dSizeB_S FLOAT
DECLARE @dSizeB_SC FLOAT
DECLARE @dThickness DECIMAL(9,2)
DECLARE @dAxs DECIMAL(9,2)

DECLARE  @dESizeB_S FLOAT
DECLARE  @dESizeB_SC FLOAT
DECLARE  @dDiffSC FLOAT

DECLARE @dR1 DECIMAL(9,2)
DECLARE @dESizeD FLOAT
DECLARE @dSizeD DECIMAL(9,2)
DECLARE @adjThick DECIMAL(9,2)
DECLARE @finalThick DECIMAL(9,2)

IF(@AXS > 0) 
   BEGIN
    IF (@AXS >= 180)
       BEGIN 
         SET @dAxs = @AXS - 90
       END
    ELSE 
       BEGIN 
         SET @dAxs = @AXS
       END 
    END
ELSE
   BEGIN 
     SET @dAxs = @AXS
   END 

SET @dR2S = ((@RI - 1.0) * 1000) / (@BC - @Sph)


SET @dDiffSC = @BC - (@Sph + @Cyl)

IF @dDiffSC = 0 
  BEGIN 
    SET @dDiffSC = @BC
  END 

SET @dR2SC = ((@RI - 1.0) * 1000) / (@dDiffSC)

SET @dESizeB_S = POWER(@dR2S,2) - POWER(@DIA /2,2)
SET @dESizeB_SC = POWER(@dR2SC,2) - POWER(@DIA /2,2)

SET @dSizeB_S = @dR2S - Sqrt(@dESizeB_S)
SET @dSizeB_SC = @dR2SC - Sqrt(@dESizeB_SC)
SET @dSizeA = @CT

IF @dSizeB_S > @dSizeB_SC
   BEGIN 
     SET @dSizeB = @dSizeB_S
   END 
ELSE 
   BEGIN 
     SET @dSizeB = @dSizeB_SC
   END 

SET @dSizeC = @dSizeA + @dSizeB

SET @dR1 = (@RI - 1.0) * 1000 / (@BC)
SET @dESizeD = POWER(@dR1,2) - POWER(@DIA /2,2)

IF @dR1 > @dR2S
    BEGIN
        SET @dSizeD = @dR1 - sqrt(@dESizeD)
    END
ELSE
    BEGIN
        SET @dSizeD = @dSizeB
    END

SET @adjThick = @dSizeC - @dSizeD

IF @dSizeD > 3.50
    BEGIN
        SET @dSizeD = @dSizeD - 3.50
        SET @finalThick = @adjThick + @dSizeD + 1.50
    END
ELSE
    BEGIN
        SET @finalThick =  @adjThick + 1.50
    END

RETURN @finalThick

END

Из сохраненной функции SQL, приведенной выше, я пытаюсь получить из нее простое приложение C #.

Product:

public float calc2(decimal sph, decimal cyl, decimal bc, decimal dia, decimal ct, decimal Axs)
        {   

decimal ri = 1.74M, dAxis, dR2S, dR2SC, dR1; decimal dDiffSC, dSizeB_S, dSizeB_SC, dESizeD, dESizeB_S, dESizeB_SC; decimal dSizeA, dSizeB, dSizeC, dSizeD; decimal adjthick; float finaloutput; dAxis = Axs > 0 ? (Axs >= 180 ? Math.Round(Axs - 90,2) : Math.Round(Axs,2)) : Math.Round(Axs,2); dR2S = Math.Round((((Math.Round(ri, 2) - 1.0M) * 1000)/(bc - sph)),2); dDiffSC = bc - (sph + cyl); dDiffSC = dDiffSC == 0 ? bc : dDiffSC; dR2SC = Math.Round((((Math.Round(ri, 2) - 1.0M) * 1000) / (dDiffSC)),2); dESizeB_S = dPow(dR2S, 2M) - dPow((dia/2), 2M); dESizeB_SC = dPow(dR2SC, 2M) - dPow((dia/2), 2M); dSizeB_S = dR2S - (decimal)Math.Sqrt((double)dESizeB_S); dSizeB_SC = dR2SC - (decimal)Math.Sqrt((double)dESizeB_SC); dSizeA = Math.Round(ct, 2); dSizeB = dSizeB_S > dSizeB_SC ? Math.Round(dSizeB_S,2) : Math.Round(dSizeB_SC,2); dSizeC = Math.Round((dSizeA + dSizeB),2); dR1 = Math.Round((((Math.Round(ri, 2) - 1.0M) * 1000) / (bc)),2); dESizeD = dPow(dR1, 2M) - dPow((dia/2), 2M); dSizeD = dR1 > dR2S ? Math.Round((dR1 - (decimal)Math.Sqrt((double)dESizeD)),2): Math.Round(dSizeB,2); adjthick = Math.Round((dSizeC - dSizeD),2); finaloutput = dSizeD > 3.50M ? (float)Math.Round((adjthick + (dSizeD - 3.50M) + 1.50M),2) : (float)Math.Round((adjthick + 1.50M),2); return finaloutput; } public static decimal dPow(decimal x, decimal y) { Double X = (double)x; Double Y = (double)y; return (decimal)System.Math.Pow(X, Y); }

Однако после нескольких часов проб и ошибок при изменении типов данных (двойные, десятичные, с плавающей запятой и т. д.). Я все еще получаю несоответствия.

Используя эти значения:

  1. сф = -2,00
  2. цил = 0,00
  3. ri = 1.74
  4. bc = 1.00
  5. диаметр = 75
  6. ct = 1.10
  7. ось = 180

После выполнения хранимой функции в SQL.
Я получил результат 4.46
После выполнения кода на C#.
Я получил результат 4.52.

Это небольшое расхождение, но по мере изменения sph и cyl разница, создаваемая двумя методами, также увеличивается.

Вопрос:
Есть ли проблема в типах данных, которые я использую?
Отличается ли поведение SQL-сервера от C#?
Есть ли другие возможные причины этих расхождений?


person Hexxed    schedule 02.03.2016    source источник
comment
Есть простой способ узнать, где начинается несоответствие. Упростите обе программы, чтобы просто выполнить первое вычисление. Дают ли они одинаковые результаты? Если нет, все готово. Вы нашли разницу. Если да, добавьте еще одну строку. Повторяйте, пока не получите линию, дающую разные результаты. Это строка с ошибкой.   -  person Eric Lippert    schedule 02.03.2016
comment
@EricLippert Я могу легко сделать это на C #, но на сервере SQL - другая история.   -  person Hexxed    schedule 02.03.2016
comment
Этот вопрос также может быть полезен stackoverflow.com/questions/3152439/   -  person Liesel    schedule 02.03.2016
comment
Возможно, вы захотите проверить огромное количество неявных преобразований и констант, которые вы используете. И выполнение математических расчетов вручную также может помочь вам увидеть, в чем проблема :)   -  person Luaan    schedule 02.03.2016
comment
@LesH Хорошо, я проверю это.   -  person Hexxed    schedule 02.03.2016
comment
Вы запускаете это в окне запроса, используя SQL Server Management Studio, SSDT или что-то подобное? Добавьте строку после END -- SELECT fn_LensThickCalcAC(-2.00, 0.00, 1.74, 1.00, 75, 1.10, 180) --, которая будет выводить результат каждый раз, когда вы запускаете пакет. Затем вы можете закомментировать строку за строкой (SQL Server использует -- в начале строки для комментариев).   -  person Zev Spitz    schedule 02.03.2016
comment
@Luaan Я уже сделал это вручную и получил тот же ответ, что и мой код C #. Мне все еще интересно, почему код SQL отличается.   -  person Hexxed    schedule 02.03.2016
comment
@ZevSpitz Я запускаю SQL Server Management Studio. тоже пробую спасибо.   -  person Hexxed    schedule 02.03.2016
comment
Голосуем за закрытие, так как это не самый короткий код, необходимый для воспроизведения проблемы. В качестве отправной точки: если ваш код содержит более одного оператора if-else (или условного оператора), он, вероятно, длиннее, чем необходимо. Все такие операторы должны быть заменены либо их блоком if, либо их блоком else.   -  person Brian    schedule 02.03.2016


Ответы (1)


ОБНОВЛЕНИЕ: понял. Мне нужно было изменить типы данных dia и axs на SMALLINT/Int16 Спасибо за помощь

person Hexxed    schedule 02.03.2016