Problem z przenoszeniem wartości

Użytkowanie arkusza kalkulacyjnego
wojtul60
Posty: 32
Rejestracja: sob sie 29, 2015 7:52 pm

Problem z przenoszeniem wartości

Post autor: wojtul60 »

Witam!!!
Proszę o podpowiedź gdzie leży przyczyna błędu.
Mam makro w którym w jednej z procedur deklaruję zmienną Ilosc jako single (dim Ilosc as single)
Pobieram wartość komórki z jednego arkusza do tej zmiennej a następnie w innym miejscu procedury kopiuję do komórki w innym arkuszu.
poleceniami
oCell=oSheet.getcellbyposition (2,Numer_wiersza+6)
Ilosc=oCell.value
a następnie po uaktywnieniu odpowiedniego arkusza i wybraniu komórki docelowej
oCell.value=Ilosc
'
Problem polega na tym, że przenoszona wartość w komórce źródłowej ma wartość np. =3,08
a po przeniesieniu wartość ta= 3,799999 i jeszcze parę cyfr.
Problem znika gdy zmiennej "Ilosc" w procedurze nie deklaruję jako single
Nie rozumiem dlaczego tak się dzieje.
Pozdrawiam
open Office 4 na win7
belstar
Posty: 654
Rejestracja: czw mar 17, 2011 9:08 am

Re: Problem z przenoszeniem wartości

Post autor: belstar »

wojtul60 pisze:Problem polega na tym, że przenoszona wartość w komórce źródłowej ma wartość np. =3,08
a po przeniesieniu wartość ta= 3,799999 i jeszcze parę cyfr.
W helpie jest napisane:
Zmienne typu Single
Zmienne typu Single (pojedyncza precyzja) mogą przyjmować wartości dodatnie lub ujemne w zakresie od 3,402823 x 10E38 do 1,401298 x 10E-45. Są to zmienne zmiennoprzecinkowe, w których wraz ze wzrostem wartości części całkowitej zmniejsza się precyzja części ułamkowej. Zmienne typu Single są odpowiednie do obliczeń matematycznych o średniej dokładności. Obliczenia wymagają więcej czasu niż w przypadku zmiennych całkowitych, ale są szybsze niż w przypadku zmiennych typu Double (podwójna precyzja). Zmienna typu Single wymaga czterech bajtów pamięci.
wojtul60 pisze:Problem znika gdy zmiennej "Ilosc" w procedurze nie deklaruję jako single
Nie rozumiem dlaczego tak się dzieje.
To że nie deklaryujesz typu zmiennej nie oznacza że basic nie deklaruje jej typu automatycznie:

Kod: Zaznacz cały

Variant/double
Czyli nadaje jej typ jako double, jeśli ty zadeklarujesz ją jako double zachowasz jej dokładną postać, ale będzie to nadmiarowy typ (8 bajtów w pamięci)
Pewnym rozwiązanie jest deklaracja jako string (w pamięci: 1 + 1 na każdy znak), a później w kodzie konwersja na typ double (choć pewien na 100% nie jestem).

Kod: Zaznacz cały

Cell.value = Cdbl(ilosc)
W visual basicu jest dostępna deklaracja o określonej długości łańcucha

Kod: Zaznacz cały

Dim ilosc as String*3
Lecz w mojej wersji LO coś nie działa, a przy tym nie wywołuje błędu.

Więc kod mógłby wyglądać tak:

Kod: Zaznacz cały

Sub test
	Dim ilosc as String
  'Dim ilosc as String * 4
	Dim Doc As Object
	Dim Sheet As Object
	Dim Cell As Object   
 
	Doc = ThisComponent
	Sheet = Doc.Sheets(0)
	 
	Cell = Sheet.getCellRangeByName("A1")
	ilosc= cell.string
	Cell = Sheet.getCellRangeByName("A2")
	Cell.value = Cdbl(ilosc)
End Sub
LibreOffice 5.1.2.2 Ubuntu 16 LTS
wojtul60
Posty: 32
Rejestracja: sob sie 29, 2015 7:52 pm

Re: Problem z przenoszeniem wartości

Post autor: wojtul60 »

Witam!!!
Te informacje z pomocy były mi znane- ale wydawało mi się że 4 bajty wystarczą na wartość 3,08.
Nie wiem jak OO wykorzystuje te cztery bajty które ma do dyspozycji na zmienne typu single i mimo że w moim przypadku po przecinku są tylko
dwie cyfry znaczące to jak widać nie jest to takie proste.
Dzięki
open Office 4 na win7
Jan_J
Posty: 4579
Rejestracja: pt maja 22, 2009 1:20 pm
Lokalizacja: Wrocław

Re: Problem z przenoszeniem wartości

Post autor: Jan_J »

Bajty wykorzystuje się tak, że wartości całkowitoliczbowe (integer, longint) są pamiętane w układzie dwójkowym, a wartości zmiennopozycyjne (single, double) jako pary liczb całkowitych. Pierwsza liczba przechowuje znak i cyfry znaczące, a druga względne położenie przecinka/kropki dziesiętnej. Każda z tych danych ma stałą pojemność, tj. liczbę pamiętanych cyfr dwójkowych.
Problem polega na tym, że ułamki binarne mają skończoną liczbę cyfr tylko wtedy, gdy opisują ułamki niewłaściwe o mianownikach będących potęgami dwójki. W przypadku ułamków dziesiętnych skończoność wymaga, by mianownik był iloczynem potęg dwójki i potęg piątki, to znaczy dzielników bazy systemu pozycyjnego.
Np. liczba 5/2 jako ułamek dziesiętny ma postać 2,5, a jako binarny 10,1. Natomiast 3,08 odpowiada ułamek 308/100 = 77/25, skąd widać, że odpowiedni ułamek binarny ma nieskończone rozwinięcie. Podobnie będzie z liczbą 0,1 == 1/10. Tak! komputery na ogół pamiętają wartość 0,1 z błędem!
W takim razie dlaczego w przypadku double tego nie ma? Jest, tylko nie widać. W uproszczeniu: konwersja single -> double nie zmniejsza błędu, tylko zwiększa precyzję zapisu. Podczas prezentacji wartości liczby dokonywana jest konwersja z double do napisu, która ukrywa/koryguje błąd na ostatniej cyfrze. Jeśli wcześniej skonwertowano wartość z single, błąd jest większy i nie jest korygowany.
JJ
LO (24.2|7.6) ∙ Python (3.12|3.11|3.10) ∙ Unicode 15 ∙ LᴬTEX 2ε ∙ XML ∙ Unix tools ∙ Linux (Rocky|CentOS)
ODPOWIEDZ