Chciałbym wiedzieć, czy obecne cpusy unikają pomnożenia dwóch liczb, gdy przynajmniej jedno z nich jest zerem. DziękiCzy współczesne cpus pomija multiplikacje przez zero?
Odpowiedz
Spodziewałbym się, że nowoczesny procesor będzie miał w sobie coś takiego.
Nowoczesne procesory - co przez to rozumiesz? Masz na myśli najczęściej używane (np. X86, AMD64, ARM) lub ostatnio opracowane. Każda architektura procesora ma swoje własne właściwości. Co więcej, każda firma (np. Intel lub AMD) może sprawić, że procesor będzie różny (zwykle jest to tajemnica firmy).
W odpowiedzi na pytanie wątpię w to. Wiesz, nawet sprawdzanie, czy liczba jest równa zero dwa razy, zanim KOŃNE mnożenie będzie zbyt duże, jeśli zważysz, jak niski procent operacji mnożenia jest zoptymalizowany.
Optymalizacja taka spowodowałaby wzrost kosztu procesora.
Załóżmy, że w programie standardowym jest 1% mnożenia przez zero (i prawdopodobnie jest znacznie niższy). Oznaczałoby to, że porównanie do zera musiałoby być 200 razy szybsze niż pomnażanie, aby być tylko narzutem na obciążenie (i wiele więcej, aby było to przydatne w praktyce).
Myślę, że zbytnio patrzysz na to pytanie z ludzkiej perspektywy. Kiedy się mnożysz, wyraźnie zobaczysz, że jeden z multiplików jest zerowy i kończy. Jednak w przypadku komputerów sytuacja wygląda zupełnie inaczej. Komputer faktycznie musi sprawdzić wszystkie 64 lub 32 bity, aby mieć pewność, że coś jest równe zeru.
- Nie martwiłbym się, gdybym był tobą. Producenci procesorów i twórcy kompilacji dokładają wszelkich starań, aby zmaksymalizować wydajność. Mają literacką myśl o wszystkim.
Zgadzam się, multiplikacje są szybkie. Wygląda na to, że nadmierna optymalizacja pozwala sprawdzić każdą wartość przed rozdaniem. Założę się, że procesor właśnie wykonuje operację. –
Pewnie. :) Myślę, że moja odpowiedź to obejmuje. Szczególnie ostatni akapit. –
Zapominasz o ile szybciej może to być zrobione w sprzęcie. – Puppy
Różni się to znacznie w zależności od procesora i (w niektórych przypadkach) typu (typów) operandów.
Starsi/prostszych procesorów zazwyczaj używają algorytmu mnożenia coś takiego:
integer operator*(integer const &other) {
unsigned temp1 = other.value;
unsigned temp2 = value;
unsigned answer = 0;
while (temp1 != 0) {
if (temp1 & 1)
answer += temp2;
temp2 <<= 1;
temp1 >>=1;
}
return integer(answer);
}
Ponieważ pętla wykonywana tylko wtedy, gdy/jeśli temp1 != 0
, pętla nie wykona oczywiście jeśli temp1
zaczyna się jako 0 (ale jak zapisany tutaj, nie będzie próbował żadnej optymalizacji dla drugiego argumentu będącego 0).
Jest to jednak algorytm jednoczęściowy. Na przykład, podczas mnożenia 32-bitowych operandów, jeśli każdy bit ma 50:50 szansy na ustawienie, spodziewamy się średnio około 16 iteracji.
Nowszy, zaawansowany procesor zazwyczaj działa z co najmniej dwoma bitami naraz, a może nawet więcej. Zamiast pojedynczego elementu sprzętowego wykonującego wiele iteracji, zwykle potokuje operację za pomocą oddzielnego (choć w zasadzie identycznego) sprzętu dla każdego etapu mnożenia (chociaż zwykle nie będą one wyświetlane jako oddzielne etapy na normalnym schemacie rurociągu dla procesora).
Oznacza to, że wykonanie będzie miało takie samo opóźnienie (i przepustowość) niezależnie od argumentów.Średnio poprawia to trochę opóźnienie i przepustowość, ale prowadzi do tego, że każda operacja odbywa się z tą samą prędkością, niezależnie od operandów.
Jak to by było "pomijanie" mnożenia? Jeśli daje wynik 0, bez względu na to, jak szybko to robi, to w rzeczywistości wykonało mnożenie. –