mssql zaokrąglanie arytmetyczne różna ilość miejsc po przecinku

0

Sprawa jest dość skomplikowana, liczę kwotę narzutu, na którą składa się mnożenie kilku różnych wartości. Wyniki wychodzą różne, od 1 do 8 miejsc po przecinku, to jest raczej ok, bo nie mam na to wpływu (tak liczy aplikacja). Potrzebuje, aby zestawienie które tworze, zaokrąglało wyniki do 2 miejsc po przecinku i dawało takie same wyniki, jak ta aplikacja. Problem prawie udało się rozwiązać, niestety są różnice 0,01 lub 0,02, które są niedopuszczalne. Dla przykładu:
944,90928 -> powinno zwracać 944,91 - OK
2651,85158664 -> powinno zwracać 2651,85 zwraca 2651,87
15572,36465748 -> powinno zwracać 15572,44 zwraca 15572,42

Każda z powstałych liczb jest sumą kilku wpisów, różnej ilości dla każdej z nich. Rozwiązuje w tej chwili sprawę odrębną funkcją, lecz jak widać wyniki bardzo nieznacznie są inne od oczekiwanych.

 ALTER FUNCTION [dbo].[fn_zaokraglanie_arytm] 
(
	@kwota float
)
RETURNS float
AS
BEGIN
	RETURN CASE WHEN (cast((@kwota * 10000)/10 as int)%10)=5
	THEN Floor(@kwota * 100)/100+0.01
	ELSE ROUND(@kwota,2)
		END

	-- Return the result of the function
	RETURN round(@kwota,2)

END

Przez funkcję przechodzi każda z sumowanych na końcu kwot.

0

A nie powinno czasem zwracać 15572,36 ? - Vardamir 2 minuty temu

być może powinno, ale jak napisałem, nie mam wypływu na działanie aplikacji,a wynik muszę mieć taki sam.

przeniosłem wywołanie funkcji, aby mieliło tylko wynik sumowania, a nie każdy ze składników. Pomogło to w przypadku liczby
2651,85158664 (zwraca 2651,85)

Problemem pozostaje feralna dość liczba
15572,36465748 -> powinno zwracać 15572,44 w tej chwili zwraca 15572,37

Znalazłem też inne liczby, które źle się liczą:
4484,898885 zwracać powinno 87 zwraca 9
7853,9877 zwracać powinno 97 zwraca 99
6816,3117323 zwracać powinno 32 zwraca 31

Liczby wskazują, jakby program źle liczył sumy które wyświetla...

0

a dlaczego nie ROUND(liczba, 2)?

PS. a i w tagach piszesz mysql a w kodzie dajesz funkcję z mssql - może się zdecyduj

ps2. sprawdzałeś ile te liczby bez zaokrągleń wynoszą? - może masz problem nie z zaokrąglaniem ale z liczeniem sum

0

Myślę, że problemem jest nakładanie się na siebie małych różnic podczas mnożenia po stronie aplikacji i po stronie bazy. Ciężko tu coś poprawić bo to zachowanie jest różne w zależności od danych wejściowych.
@abrakadaber
Kolega chce dopasować prawidłowe (wg bazy danych) zaokrąglenia do danych z aplikacji ;D Przynajmniej ja tak to widzę.

0

poprawka mssql ;)
aplikacja korzysta z tej samej bazy, jednak do kodu źródłowego aplikacji nie mam dostępu. Z tego co wiem, tam są zastosowane różne cuda, wykorzystanie excela i inne...
Różnice są bardzo niewielkie, wiele wpisów liczy się dobrze, niestety sporo też nie, a nawet 1gr różnicy już jest błędny.
Być może dobrym pomysłem jest prezentacja kodu, lekko tylko modyfikując nazwy tabel:

 (SELECT ISNULL(CAST(dbo.fn_zaokraglanie_arytm(cast(SUM(
												CASE WHEN Projekt.nazwa = 'Bezosobowy' OR Projekt.nazwa = 'Osobowy' THEN
												(projekt_real_zal.kwota + (projekt_real_zal.kwota * projekt_real_zal.ubez_sp_wsp / 100 ) + (projekt_real_zal.kwota * projekt_real_zal.ubez_wyp_wsp / 100))
												ELSE projekt_real_zal.kwota 
												END 
												* projekt_real_zal.WREZ_NARZUT_WSP/100 
												)as float)) as float), 0) AS Expr1
							  FROM          dbo.Watek AS watek 
							  INNER JOIN dbo.WatekProjekt AS Projekt ON watek.ID_WATEK = Projekt.wpj_id_w 
							  INNER JOIN dbo.WatekRealizacjaZaliczki AS projekt_real_zal ON projekt_real_zal.wrez_id_proj = Projekt.id_w_projekt
							  WHERE     
								 (Projekt.wpj_id_w = a.ID_WATEK) 
								 AND (projekt_real_zal.WREZ_TYP = 2) 
								 AND (
										DATEPART(yy, projekt_real_zal.WREZ_DATA) = DATEPART(YY, GETDATE())
									  )
							  ) AS Narzut,
0
peterkovic napisał(a):

Problemem pozostaje feralna dość liczba
15572,36465748 -> powinno zwracać 15572,44 w tej chwili zwraca 15572,37

ale to jakbyś nie zaokrąglał to 15572,__36__465748 nigdy Ci nie da 15572,44

0
abrakadaber napisał(a):
peterkovic napisał(a):

Problemem pozostaje feralna dość liczba
15572,36465748 -> powinno zwracać 15572,44 w tej chwili zwraca 15572,37

ale to jakbyś nie zaokrąglał to 15572,__36__465748 nigdy Ci nie da 15572,44

Logicznie rzecz biorąc jak najbardziej zgadzam się z Tobą, ale aplikacja temu przeczy, dlatego takie problemy... mały wycinek z aplikacji:

user image

0

no ale przy takich wynikach nie jesteś w stanie tego zrobić dobrze - nie da się zaokrąglić czegoś z ,36 na ,44 choćby nie wiem jakie cyfry były od trzeciego miejsca po przecinku. Nie da się i już.
To co dałeś to co to jest? Bo kawałek arkusza to i ja mogę sobie wkleić. Jeśli chcesz to daj WSZYSTKIE wartości składowe, których suma daje to magiczne 15572,44 to może ktoś wymyśli jak je sumować

0

To jest przykład że jednak się jakoś da.. osobiście po różnych przekształceniach kodu i zaokrąglania w różnych dziwnych miejscach udało mi się osiągnąć dla tego przypadku "42", jednak wtedy inne przypadki się rozsypują i mają różnice 0,01 lub 0,02 w górę lub dół.
Niestety całego arkusza udostępnić nie mogę.

0

Nie da się, Ty po prostu przekształcasz metodę jaką uzyskujesz ten wynik, a nie zaokrąglasz go. Tak jak już wcześniej mówiłem, nie będziesz w stanie zgodzić wszystkich wyników. Powodem jest to, że mimo działania na tych samych danych korzystasz z dwóch silników do liczenia tego.

0
  1. 42 to nadal nie jest 44
  2. czego oczekujesz od nas? Mamy ci wywróżyć metodę bez żadnych danych?
0

Z tego co widzę to aplikacja działa źle a ty próbujesz dostosować swój kod żeby działał tak samo źle.

0

Prawdopodobnie macie rację co do błędów aplikacji, sprawa musi zostać skonsultowana w takim razie z autorem programu. Dzięki za sugestie.

0

Poproś autora o ten kawałek kodu w którym przeprowadza te kalkulacje.Widziałem kiedyś podobną sytuację do Twojej, problem polegał na tym, że
w aplikacji zmienna była typu int, do tej zmiennej przypisywana była w pewnych warunkach wartość Double.Java nie wyrzucała błędu tylko ucinała wartości po przecinku.
Przykład:

for (int i=1;i<4;i++){
int c= 11/i;
JOptionPane.showMessageDialog(null,c);
}

W tym przypadku Java wyświetla 11,5,3, zamiast 11, 5.5, 3,666666666666667. To jest tylko przykład, ale ogólnie chodzi o pokazanie problemu typów zmiennych.
Tak jak napisali inni wcześniej, nie ma sensu dostosowywanie działania do wyniku, nawet jeżeli teraz jakimś cudem uda Ci się to zrobić to w przyszłości problem powróci ze zdwojoną siłą.

Pozdrawiam i powodzenia!

1 użytkowników online, w tym zalogowanych: 0, gości: 1