Jako programista C i programista C #, jedną z rzeczy, których nie lubię w C #, jest to, jak pełne są funkcje matematyczne. Za każdym razem, gdy będziesz musiał na przykład użyć funkcji Sin, cosinus lub power, musisz przygotować klasę statyczną Math. Prowadzi to do bardzo długiego kodu, gdy samo równanie jest dość proste. Problem staje się jeszcze poważniejszy, jeśli musisz typować typy danych. W rezultacie, moim zdaniem, cierpi czytelność. Na przykład:
double x = -Math.Cos(X) * Math.Sin(Z) + Math.Sin(X) * Math.Sin(Y) * Math.Cos(Z);
W przeciwieństwie do zwykłego
double x = -cos(X) * sin(Z) + sin(X) * sin(Y) * cos(Z);
Dotyczy to również innych języków, takich jak Java.
Nie jestem pewien, czy to pytanie rzeczywiście ma rozwiązanie, ale chciałbym wiedzieć, czy istnieją jakieś sztuczki używane przez programistów C # lub Java w celu poprawy czytelności kodu Math. Zdaję sobie jednak sprawę, że C # / Java / etc. nie są językami matematycznymi, takimi jak MATLAB lub podobnymi, więc ma to sens. Ale czasami trzeba jeszcze napisać kod matematyczny i byłoby wspaniale, gdyby uczynić go bardziej czytelnym.
źródło
using System.Math; … double x = -Cos(X) * Sin(Z) + Sin(X) * Sin(Y) * Cos(Z);
.Odpowiedzi:
Można zdefiniować funkcje lokalne wywołujące globalne funkcje statyczne. Mamy nadzieję, że kompilator wstawi opakowania, a następnie kompilator JIT wygeneruje ścisły kod zestawu dla rzeczywistych operacji. Na przykład:
Możesz także tworzyć funkcje, które łączą typowe operacje matematyczne w pojedyncze operacje. Pozwoliłoby to zminimalizować liczbę przypadków, w których funkcje takie jak
sin
icos
pojawiają się w kodzie, przez co niezauważalne jest wywoływanie wywoływania globalnych funkcji statycznych. Na przykład:Pracujesz na poziomie punktów i obrotów, a ukryte funkcje wyzwalające są zakopane.
źródło
W Javie dostępnych jest wiele narzędzi, które sprawiają, że niektóre rzeczy są mniej szczegółowe, po prostu musisz o nich wiedzieć. W tym przypadku przydatny jest
static
import ( strona z samouczkiem , wikipedia ).W tym przypadku,
działa całkiem nieźle ( ideone ). Trochę ciężko jest wykonać statyczny import całej klasy Math, ale jeśli robisz dużo matematyki, to może być wymagane.
Import statyczny pozwala zaimportować pole statyczne lub metodę do przestrzeni nazw tej klasy i wywołać ją bez wymagania nazwy pakietu. Często można to znaleźć w przypadkach testowych Junit, w których
import static org.junit.Assert.*;
można znaleźć wszystkie dostępne twierdzenia .źródło
public interface Constants { final static public double PI = 3.14; }
a potempublic class Foo implements Constants
we wszystkich klasach, aby uzyskać dostęp do stałych w interfejsie. To zrobiło wielki bałagan. W wersji 1.5 dodano import statyczny, aby umożliwić pobieranie określonych stałych i funkcji statycznych bez konieczności implementowania interfejsu.import static java.lang.Math.cos;
W wersji C # 6.0 można korzystać z funkcji importu statycznego.
Twój kod może być:
Patrz: statyczne za pomocą instrukcji (wersja językowa AC # 6.0)
EDYCJA: Od wydania Visual Studio 2015, CTP wydanego w styczniu 2015, import statyczny wymaga jawnego słowa kluczowego
static
. lubić:źródło
Oprócz innych dobrych odpowiedzi tutaj, mogę również zalecić DSL dla sytuacji o znacznej złożoności matematycznej (nie przeciętne przypadki użycia, ale być może niektóre projekty finansowe lub akademickie).
Za pomocą narzędzia do generowania DSL, takiego jak Xtext , możesz zdefiniować własną uproszczoną gramatykę matematyczną, która z kolei mogłaby wygenerować klasę zawierającą formułę w języku Java (lub innym języku).
Wyrażenie DSL:
Wygenerowana moc wyjściowa:
W tak prostym przykładzie korzyści wynikające z tworzenia wtyczki gramatycznej i Eclipse nie byłyby opłacalne, ale w przypadku bardziej skomplikowanych projektów mogłoby to przynieść ogromne korzyści, zwłaszcza jeśli DSL umożliwiłoby ludziom biznesu lub naukowcom utrzymanie formalnych dokumentów w wygodnym język i zapewniamy, że ich praca została dokładnie przetłumaczona na język realizacji projektu.
źródło
W języku C # można użyć metod rozszerzenia.
Poniżej przydaje się całkiem ładnie, gdy przyzwyczaisz się do notacji „postfiks”:
Niestety pierwszeństwo operatorów sprawia, że sytuacja jest nieco brzydsza, gdy mamy do czynienia z liczbami ujemnymi. Jeśli
Math.Cos(-X)
zamiast tego chcesz obliczyć-Math.Cos(X)
, musisz podać liczbę w nawiasach:źródło
x.Sin()
wymagałbym pewnych dostosowań, ale nadużywam metod przedłużania i to byłaby osobiście moja pierwsza skłonność.C #: Wariacją odpowiedzi Randall Cooka , która podoba mi się, ponieważ zachowuje matematyczny „wygląd” kodu bardziej niż metody rozszerzenia, jest użycie opakowania, ale użycie odwołań funkcji do wywołań, a nie ich zawijanie. Osobiście uważam, że dzięki temu kod wygląda na czystszy, ale zasadniczo robi to samo.
Podrzuciłem mały program testowy LINQPad, w tym zawinięte funkcje Randalla, moje odwołania do funkcji i bezpośrednie wywołania.
Wywołania wywoływane przez funkcję zasadniczo zajmują tyle samo czasu, co wywołania bezpośrednie. Zawinięte funkcje są konsekwentnie wolniejsze - choć niezbyt duże.
Oto kod:
Wyniki:
źródło
Użyj Scali! Możesz zdefiniować operatory symboliczne i nie potrzebujesz parens dla swoich metod. To sprawia, że matematyczny sposób łatwiejszy do zinterpretowania.
Na przykład takie same obliczenia w Scali i Javie mogą wyglądać następująco:
Daje to dość szybko.
źródło