Czytałem artykuł o złych praktykach programistycznych .
Wspomniał -
„Kod jo-jo”, który konwertuje wartość na inną reprezentację, a następnie konwertuje ją z powrotem do miejsca, w którym się zaczęła (np. Konwersja dziesiętnego na ciąg znaków, a następnie z powrotem na dziesiętny lub wypełnianie ciągu, a następnie przycinanie go)
Nie rozumiem, dlaczego ten konkretny przykład, który podaje, to zły sposób na pisanie programów. Wydaje mi się, że mogę ponownie przekonwertować, jeśli sytuacja tego wymaga, aby można było użyć wartości.
Czy ktoś może wyjaśnić więcej na ten temat?
programming-practices
anti-patterns
użytkownik13107
źródło
źródło
"Roundabout code" that accomplishes in many instructions what could be done with far fewer (eg: rounding a number by converting a decimal into a formatted string, then converting the string back into a decimal)
.if the situation is so that they have to be used?
- jaka by to była sytuacja?decimal myValue = decimal.Parse(dataReader["myColumn"].ToString())
to mój wkurzony zwierzak.Odpowiedzi:
Nawet jeśli zrobić potrzebujemy zarówno numeryczne i znaków reprezentujący liczbę, to lepiej, aby przekonwertować tylko raz, a także powiesić na pierwotnej wartości, zamiast konwersji ponownie za każdym razem trzeba jedno albo drugie.
Zasadą jest, jak zawsze, że kod, który nie istnieje, nie może mieć subtelnych wad , podczas gdy kod, który istnieje, często ma. Może to zabrzmieć paranoicznie, ale doświadczenie uczy nas, że jest to właściwe. Jeśli podejdziesz do programowania ze stałym lekkim niepokojem: „Nie jestem wystarczająco inteligentny, aby zrozumieć ten złożony system”, jesteś na dobrej drodze.
źródło
Jest zły z trzech głównych powodów:
Podejrzewam, że powodem 1 jest powód, dla którego twoje źródło myślało na podstawie kontekstu, w którym zostało wspomniane.
źródło
Przeredagowałbym opis jako „kod, który konwertuje typ na inną reprezentację w celu zrobienia czegoś, co można było zrobić równie dobrze lub lepiej w oryginale, a następnie konwertuje go z powrotem. Istnieje wiele sytuacji, w których konwersja czegoś do inny typ, działając na nie i przekształcając go z powrotem jest całkowicie odpowiedni, a jego niepodanie spowodowałoby nieprawidłowe zachowanie.
Na przykład, gdy konwersja jest dobra:
jeden ma cztery
float
wartości dowolnych znaków, których wielkości mogą się różnić aż do 1000, a na końcu należy obliczyć sumę z dokładnością do 0,625 jednostek. Konwertowanie wszystkich czterech wartości nadouble
, obliczanie sumy i konwertowanie wyniku z powrotem nafloat
będzie znacznie wydajniejsze niż w przypadku jakiegokolwiek podejścia używającegofloat
samego.Wartości zmiennoprzecinkowe są co najwyżej z dokładnością do 0,5 jednostki na ostatnim miejscu (ULP). Ten przykład wymagałby, aby błąd zaokrąglania w najgorszym przypadku nie był większy niż 25% powyżej optymalnego błędu w najgorszym przypadku. Użycie podwójnej wartości da dokładność w granicach 0,5001 ULP. Podczas gdy wymóg 0.625 ULP może wydawać się wymyślony, takie wymagania są często ważne w algorytmach sukcesywnej aproksymacji. Im ściślej określone jest ograniczenie błędu, tym niższy wymóg dotyczący iteracji w najgorszym przypadku.
Na przykład, gdy konwersja jest zła:
jeden ma liczbę zmiennoprzecinkową i chce wypisać ciąg, który będzie reprezentował jego wartość w unikalny sposób. Jednym z podejść jest przekonwertowanie liczby na ciąg z określoną liczbą cyfr, próba konwersji z powrotem i sprawdzenie, czy wynik jest zgodny.
Ale w rzeczywistości jest to złe podejście. Jeśli ciąg dziesiętny reprezentuje wartość, która znajduje się prawie dokładnie w połowie odległości między dwiema wartościami zmiennoprzecinkowymi, jest dość drogi w przypadku metody ciąg-zmiennoprzecinkowy, aby zagwarantować, że zawsze da wynik bliższy
float
wartość , a wiele takich metod konwersji nie utrzymują takiej gwarancji (między innymi zrobienie tego wymagałoby w niektórych przypadkach odczytania wszystkich cyfr liczby, nawet jeśli miała ona miliardy cyfr).Metoda jest znacznie tańsza, aby zagwarantować, że zawsze zwróci wartość z dokładnością do 0,5625 jednostek na ostatnim miejscu (ULP) reprezentowanej wartości. Solidna „odwracalna” procedura formatowania dziesiętnego na ciąg powinna obliczyć, jak daleko jest wartość wyjściowa od prawidłowej wartości, i kontynuować wyprowadzanie cyfr, aż wynik znajdzie się w granicach 0,375 (ULP), jeśli nie 0,25 (ULP). W przeciwnym razie może wygenerować ciąg, który niektóre metody konwersji przetworzą poprawnie, ale inne metody konwersji nie.
Lepiej czasami wyprowadzić cyfrę, która może nie być „konieczna”, niż wypisać wartość, która może być źle zinterpretowana. Kluczową częścią jest to, że decyzja o tym, ile cyfr powinna być wyprowadzona, powinna być podejmowana na podstawie obliczeń numerycznych związanych z procesem wyjściowym, a nie na podstawie próby jednej konkretnej metody konwersji łańcucha z powrotem na liczbę.
źródło
Różne powody
Jest to bezcelowe i zwiększa złożoność - zarówno pod względem ilości kodu do pisania i obsługi, jak i ilości potrzebnego czasu procesora
Może stracić dokładność lub gorzej, całkowicie zepsuć wartość
Marnuje pamięć (potencjalnie, w zależności od języka), gdy kończy się przechowywanie większej liczby reprezentacji liczby, której potrzebujesz
Dobrą praktyką jest utrzymanie pierwszej, najdokładniejszej możliwej reprezentacji dla wszystkich otrzymywanych danych. Wykonuj wszelkie obliczenia przy użyciu tych danych i zawsze konwertuj je tylko wtedy, gdy chcesz je wydrukować lub wyświetlić w łatwiejszym do odczytania formacie.
źródło
Czemu? Ponieważ nawet najlepsi z nas mogą popełniać błędy.
Zobacz, co się stało, gdy Microsoft próbował zaimplementować format „w obie strony”, aby upewnić się, że konwersje typu float <-> są bezpieczne: https://stackoverflow.com/q/24299692/541686
źródło
Kiedy byłem w szkole (i po szkole elektrotechnicznej), uczono nas, jak się dzielić po pomnożeniu. Podziel często wiele cyfr i zaokrąglij. Mnożenie po podziale zwielokrotnia błąd podziału.
Konwersje typów są takie same, ryzykujesz utratę danych. CInt (1.3) = 1.
W moim języku Basic wykonujemy tylko konwersje typów (program VB6 spędza 90% czasu na konwersji ANSI / Unicode, dla wszystkich wywołań API wykonywanych przez środowisko wykonawcze).
Konwersja typów jest implikowana we wszystkim, co robimy.
Ciąg „5” jest drukowany z literału numerycznego.
Dosłowny ciąg znaków Unicode jest konwertowany na ciąg ANSI i wysyłany do SetWindowsTextA przez pakiet form.
Nawet to działa w zasadzie
Obecnie jestem programistą wariantowym - nawet nie myślę o typie. Po prostu polegam na automatycznych konwersjach.
W każdym razie moje 3 rękawy dla zwierząt są
Przypisywanie literałów łańcuchowych do zmiennych w celu ich użycia (marnuje pamięć i spowalnia)
Bezcelowe funkcje, kiedy kod może być wbudowany (a kompilator prawdopodobnie cofnie twoją funkcję i wstawi ją i tak)
Ustawienie wszystkich obiektów na nic jako ostatnich linii przed funkcją końcową lub końcem programu.
i czwarty dla krótkich programów
Bezcelowe ściemnianie 3 zmiennych w programie 5-liniowym.
źródło