Czy w przypadku porównań bez rozróżniania wielkości liter bardziej wydajne jest przekonwertowanie ciągu znaków na wielkie czy małe litery? Czy to w ogóle ma znaczenie?
W tym poście SO sugeruje się, że język C # jest bardziej wydajny z ToUpper, ponieważ „Microsoft zoptymalizował to w ten sposób”. Ale przeczytałem również ten argument, że konwersja ToLower vs ToUpper zależy od tego, co twoje ciągi zawierają więcej, i że zazwyczaj łańcuchy zawierają więcej małych liter, co sprawia, że ToLower jest bardziej wydajne.
W szczególności chciałbym wiedzieć:
- Czy istnieje sposób na zoptymalizowanie ToUpper lub ToLower tak, aby jeden był szybszy od drugiego?
- Czy szybsze jest porównywanie wielkich i małych liter bez rozróżniania liter i dlaczego?
- Czy są jakieś środowiska programistyczne (np. C, C #, Python, cokolwiek), w których jeden przypadek jest wyraźnie lepszy od drugiego i dlaczego?
źródło
Od firmy Microsoft w witrynie MSDN:
Czemu? Od firmy Microsoft :
Jaki jest przykład takiej postaci, która nie może odbyć podróży w obie strony?
.NET Fiddle
Dlatego też, jeśli chcesz dokonywać porównań bez rozróżniania wielkości liter, konwertujesz ciągi na wielkie, a nie małe litery.
Więc jeśli musisz wybrać jedną, wybierz wielkie litery .
źródło
i
po turecku, kiedy stanie sięİ
, a nie toI
, do czego jesteś przyzwyczajony. Ponadto jesteśmy przyzwyczajeni doI
stawania się wielkimi literamii
, ale w Turcji tak się dziejeı
.Według MSDN bardziej wydajne jest przekazywanie łańcuchów i nakazanie porównaniu ignorowania wielkości liter:
Oczywiście, jeśli w kółko porównujesz jeden ciąg, może to się nie udać.
źródło
Opierając się na łańcuchach, które mają zwykle więcej wpisów z małych liter, ToLower powinien teoretycznie być szybszy (dużo porównań, ale niewiele przypisań).
W C lub w przypadku korzystania z indywidualnie dostępnych elementów każdego ciągu (takich jak ciągi C lub typ ciągu STL w C ++), jest to w rzeczywistości porównanie bajtów - więc porównywanie
UPPER
nie różni się odlower
.Gdybyś był podstępny i
long
zamiast tego załadował łańcuchy do tablic, uzyskałbyś bardzo szybkie porównanie całego ciągu, ponieważ może on porównać 4 bajty naraz. Jednak czas ładowania może sprawić, że nie będzie to opłacalne.Dlaczego musisz wiedzieć, który jest szybszy? O ile nie robisz metrycznego zestawu porównań, jeden działający kilka cykli szybciej nie ma znaczenia dla ogólnej szybkości wykonywania i brzmi jak przedwczesna optymalizacja :)
źródło
s
i przekształcićt
w tablice longs takie, że łańcuchy są równe, jeśli tablice są równe, musisz iść w dół s i t, aż znajdziesz'\0'
znak kończący (inaczej możesz porównać śmieci za końcami łańcuchów, który może być nielegalnym dostępem do pamięci, który wywołuje niezdefiniowane zachowanie). Ale w takim razie dlaczego nie zrobić po prostu porównań, przechodząc po postaciach jeden po drugim? Z napisami C ++ można prawdopodobnie uzyskać długość i.c_str()
rzutować na along *
i porównać przedrostek długości.size() - .size()%(sizeof long)
. Mimo wszystko, wygląda na podejrzanego.Microsoft zoptymalizował
ToUpperInvariant()
, nieToUpper()
. Różnica polega na tym, że niezmiennik jest bardziej przyjazny dla kultury. Jeśli musisz wykonać porównania bez uwzględniania wielkości liter w ciągach, które mogą się różnić w kulturze, użyj niezmiennej, w przeciwnym razie wykonanie niezmiennej konwersji nie powinno mieć znaczenia.Nie mogę jednak powiedzieć, czy ToUpper () czy ToLower () jest szybsze. Nigdy tego nie próbowałem, ponieważ nigdy nie miałem sytuacji, w której wydajność miałaby tak duże znaczenie.
źródło
Jeśli wykonujesz porównanie ciągów w C #, użycie .Equals () jest znacznie szybsze zamiast konwertowania obu ciągów na wielkie lub małe litery. Kolejnym dużym plusem używania .Equals () jest to, że więcej pamięci nie jest przydzielane dla 2 nowych ciągów wielkich / małych liter.
źródło
To naprawdę nie powinno mieć znaczenia. W przypadku znaków ASCII zdecydowanie nie ma to znaczenia - to tylko kilka porównań i trochę odwrócenie w dowolnym kierunku. Unicode może być nieco bardziej skomplikowany, ponieważ istnieją znaki, które zmieniają wielkość liter w dziwny sposób, ale tak naprawdę nie powinno być żadnej różnicy, chyba że tekst jest pełen tych znaków specjalnych.
źródło
Jeśli zrobisz to dobrze, konwersja na małe litery powinna mieć niewielką, nieznaczną przewagę szybkości, ale jest to, jak wielu sugerowało, zależne od kultury i nie jest dziedziczone w funkcji, ale w konwertowanych ciągach (wiele małych liter oznacza kilka przypisań do pamięci) - konwersja na duże litery jest szybsza, jeśli masz ciąg z dużą ilością dużych liter.
źródło
To zależy. Jak stwierdzono powyżej, zwykły tylko ASCII, jest identyczny. W .NET poczytaj o Stringu i używaj go, porównując jego poprawność z elementami i18n (kultury języków i unicode). Jeśli wiesz cokolwiek o prawdopodobieństwie danych wejściowych, użyj bardziej typowego przypadku.
Pamiętaj, że jeśli wykonujesz wiele porównań ciągów, długość jest doskonałym pierwszym dyskryminatorem.
źródło
Jeśli masz do czynienia z czystym ASCII, to nie ma znaczenia. To tylko OR x, 32 vs AND x, 224. Unicode, nie mam pojęcia ...
źródło