Czy można napisać program w C, który zwielokrotnia dwie liczby bez użycia operatorów mnożenia i dodawania?
Znalazłem to na stosie przepełnienia . Pomóż temu biednemu programiście rozwiązać jego problem. I proszę, nie udzielaj odpowiedzi typu c = a/(1/((float)b))
, który jest dokładnie taki sam jak c = a*b
. (I jest już podany jako odpowiedź).
Odpowiedź z największą popularnością 19 stycznia 2014 r. Wygrywa.
Uwaga: jest to pytanie trollujące kod . Proszę nie brać poważnie pytania i / lub odpowiedzi. Więcej informacji znajduje się w trollingu kodu .
Odpowiedzi:
Zawsze używaj rekurencji
Recusion to właściwa droga!
źródło
??::
bez nawiasów, jeden za rozwiązanie problemu bez próby zmiany zasad;)inc
Funkcja sprawdza swój argument, aby sprawdzić, czy najniższym bitem jest1
; jeśli tak, wywołuje się na pozostałych górnych bitach argumentu i zwraca wynik z tym samym bitem niskim, który został sprawdzony0
, a jeśli nie (tj. bitem najniższym0
), zamienia to na0
a1
i zwraca wynik . Proces jest bardzo podobny do tego, co zrobiłbyś, gdybyś dodawał wartości ręcznie, cyfra binarna po cyfrze binarnej.Będziesz musiał skompilować program za każdym razem, ale robi to mnożenie dodatnich liczb całkowitych dokładnie w dowolnej wersji C lub C ++.
źródło
"%zu"
ciągu formatu.sizeof(char[A][B])
zadziała (chyba że A <= 0 lub B <= 0 lub A * B przepełnia się, w takim przypadku powinieneś otrzymać błąd typu „zły typ”)main(){return sizeof(char[A][B]);}
a ty skompilujesz używająccc -DA=6 -DB=7 a.c; ./a.out; echo $?
Jeśli masz trochę niedokładności, możesz użyć metody Monte Carlo :
Przykład:
Myślę, że to może być wystarczająco dobre;)
źródło
++
operatora.-= -1
|= 1
(będzie działać na 50% liczb, w 100% przypadków)printf
przyrost:printf("%*cc%n\n", count, &count, 'c');
(Drukuje „c” zliczanie razy, potem kolejne „c” i zapisuje liczbę znakówcount
Ponieważ nie podałeś wielkości, zakładam, że masz na myśli dwie jednobitowe liczby.
Jeśli chcesz maksymalnie wydajnej implementacji, użyj następującej niewielkiej implementacji:
Zauważ, że nadal akceptuje tylko bity, mimo że typy są niejawnymi liczbami całkowitymi - zajmuje mniej kodu i dlatego jest bardziej wydajny. (I tak, to się kompiluje.)
źródło
return a && b;
. Jest krótszy, więc jest szybszy.return a&b;
.#include<stdbool.h>
zdefiniowaćtrue
ifalse
.#include<stdbool.h>
wydaje się być tylko trzy#define
s, które można zrobić samemu (true
,false
,bool
, i flagi z okazji, że został aktywowany). Możesz także wziąć lewę z jednej z pozostałych odpowiedzi i użyć niejawnieint
dla „krótkiej” wersji.Oto prosty skrypt powłoki, aby to zrobić:
AKTUALIZACJA: Oczywiście, aby to zrobić w C, po prostu ją zawiń
exec("bash", "-c", ...)
. (Dzięki, AmeliaBR)źródło
%20
aby uniknąć używania jakichkolwiek+
znaków.) Ale nadal musisz przeanalizować dane wyjściowe (w C), aby uzyskać z nich wartość. Co będzie szczególnie trudne, ponieważ wyjście wydaje się być obrazem, a nie tekstem. Analiza składni HTML plus OCR może sprawić, że będzie to najlepsza możliwa odpowiedź na ten problem.Zróbmy rekurencyjne wyszukiwanie o połowę między INT64_MIN a INT64_MAX!
PS Z radością sigsegv z pewnymi wartościami. ;)
źródło
Niestety działa to tylko w przypadku liczb całkowitych.
Ponieważ dodawanie jest niedozwolone, najpierw stwórzmy operator inkrementacji:
Następnie musimy obsłużyć znak. Najpierw znajdź bit znaku:
Następnie weź znak i wielkość każdego argumentu. Aby zanegować liczbę w uzupełnieniu do dwóch, odwróć wszystkie bity i dodaj jeden.
Aby pomnożyć dwie dodatnie liczby całkowite, możemy użyć geometrycznego znaczenia mnożenia:
trolle:
a++
tak naprawdę liczy się jako dodawanie? Założę się, że nauczyciel zamierzał na to pozwolić.<<
jest w rzeczywistości pomnożeniem przez potęgę dwóch, więc technicznie należy go zabronić.-1
nie jest najlepszym sposobem na znalezienie bitu znaku. Nawet jeśli nie ma wbudowanej stałej, można wykonać logiczne przesunięcie w prawo o -1, a następnie odwrócić wszystkie bity.MIN_INT
(AKAsignBit
) jest ujemna, ta wartość jest dzielona na tę wartość. Na szczęście nadal działa w połowie przypadków, ponieważMIN_INT * [even number]
powinno wynosić zero.PonadtoplusOne
przerywa-1
, powodując nieskończone pętle za każdym razem, gdy wynik przepełnia się.plusOne
działa dobrze dla dowolnej wartości. Przepraszam za zamieszanie.źródło
(x ^ y) | ((x & y) << 1)
nie działa, nie propaguje przenoszenia, gdy x lub y i przeniesienie są prawdziwe w tej samej pozycji :)Działa również dla liczb zmiennoprzecinkowych:
źródło
Wszyscy wiedzą, że Python jest łatwiejszy w użyciu niż C. A Python ma funkcje odpowiadające każdemu operatorowi, w przypadkach, gdy nie można go używać. Jaka jest dokładnie nasza definicja problemu, prawda? Więc:
źródło
Żadna z pozostałych odpowiedzi nie jest teoretycznie poprawna. Jak mówi pierwszy komentarz do pytania:
Musimy zdefiniować mnożenie i liczby, zanim odpowiedź będzie w ogóle możliwa. Gdy to zrobimy, problem stanie się banalny.
Najpopularniejszym sposobem osiągnięcia tego na początku logiki matematycznej jest zbudowanie porządków von Neumanna na podstawie teorii zbiorów ZF , a następnie użycie aksjomatów Peano .
To oczywiście przekłada się na C, zakładając, że masz typ zestawu, który może zawierać inne zestawy. Nie musi zawierać niczego poza zestawami, co czyni go trywialnym (żaden z tych rzutujących
void*
nonsensów w większości bibliotek zestawów), więc zostawię implementację jako ćwiczenie dla czytelnika.Po pierwsze:
Jeśli chcesz rozszerzyć to na liczby całkowite, racjonalne, rzeczywiste, surrealne itp., Możesz - z nieskończoną precyzją (zakładając, że masz nieskończoną pamięć i procesor), uruchomić. Ale jak to słynie Kroenecker, Bóg stworzył liczby naturalne; wszystko inne jest dziełem człowieka, więc naprawdę po co zawracać sobie głowę?
źródło
Jeśli uważasz, że hack a [b] jest oszustwem (ponieważ jest to naprawdę dodatek), to działa zamiast tego. Ale wyszukiwanie tabel obejmuje również dodawanie wskaźnika.
Zobacz http://en.wikipedia.org/wiki/IBM_1620 - konwerter, który faktycznie dodawał za pomocą tabel odnośników ...
Coś satysfakcjonującego w używaniu mechanizmu tabeli w celu „przyspieszenia” operacji, którą można by faktycznie wykonać za pomocą jednej instrukcji.
źródło
*
char (chociaż nie jest to mnożenie)Nie jestem pewien, co stanowi „oszustwo” w tych „kodowych trollach”, ale to zwielokrotnia 2 dowolne liczby całkowite w czasie wykonywania, bez operatora
*
lub+
przy użyciu standardowych bibliotek (C99).źródło
Moje rozwiązanie trollowe dla
unsigned int
:źródło
Jest tu wiele dobrych odpowiedzi, ale nie wygląda na to, aby wiele z nich skorzystało z faktu, że nowoczesne komputery są naprawdę potężne. W większości procesorów jest wiele jednostek przetwarzania, więc po co używać tylko jednego? Możemy to wykorzystać, aby uzyskać doskonałe wyniki wydajności.
Oto przykład jego użycia:
#pragma omp parallel
Dyrektywa sprawia OpenMP dzielić każdą część pętli for do innej jednostki wykonawczej, więc jesteśmy pomnożenie równolegle!Pamiętaj, że musisz użyć
-fopenmp
flagi, aby poinformować kompilator o użyciu OpenMP.Części trolli:
for
pętli - każdy wątek uruchamia pętlę.answer--
; przez większość czasu nie pojawia się, ale czasami powoduje niedokładne wyniki.źródło
Niestety mnożenie jest bardzo trudnym problemem w informatyce. Najlepszym rozwiązaniem jest użycie podziału:
źródło
W prawdziwym życiu zwykle reaguję trollingiem na wiedzę, więc oto odpowiedź, która wcale nie trolluje. Działa dla wszystkich
int
wartości, o ile widzę.Jest to, według mojego najlepszego zrozumienia, bardzo podobne do tego, w jaki sposób procesor faktycznie może zwielokrotniać liczby całkowite. Po pierwsze, upewniamy się, że co najmniej jeden z argumentów (
a
) jest dodatni, poprzez włączenie znaku zarówno jeślia
jest ujemny (i nie, odmawiam liczenia negacji jako rodzaju dodawania lub mnożenia). Następniewhile (a)
pętla dodaje przesuniętą kopięb
wyniku do każdego ustawionego bitua
.do
Pętla implementujer += x
używania i XOR, a przesunięcie w co wyraźnie zestaw pół dodatkami, z bitami carry zawraca sięx
aż nie ma więcej (prawdziwy procesor będzie używać pełnych adders, który jest bardziej wydajny, ale C nie robi” t mieć operatorów, których potrzebujemy, chyba że policzysz+
operatora).źródło
while(a)
pętla nigdy się nie kończy.źródło
while(C/A != B || C%A)
?Wrzucając to do miksu:
Ze strony informacyjnej .
- Wprowadzenie do kodu czegoś wyjątkowo niedopuszczalnego lub nierozsądnego, którego nie można usunąć bez wyrzucenia wszystkiego, co sprawia, że odpowiedź jest całkowicie bezużyteczna dla OP.
- […] Chodzi o odrabianie pracy domowej w języku, który leniwy OP może uznać za akceptowalny, ale nadal go frustruje.
źródło
źródło
Pewnie:
Ale to oczywiście oszustwo; najwyraźniej chce być w stanie podać dwie liczby, prawda?
źródło
Nie ma arytmetyki takiej jak arytmetyka wskaźnikowa:
Funkcja
f
implementuje mnożenie.main
po prostu wywołuje to z dwoma argumentami.Działa również dla liczb ujemnych.
źródło
a
, tak, negatywneb
Nie sądzę. Ale można to naprawić na wiele kreatywnych sposobów. Najprostszym byłoby znak_a ^ = znak_b, znak_b = 0.DO#
Myślę, że odejmowanie i negowanie są niedozwolone ... W każdym razie:
źródło
C z właściwościami SSE (ponieważ wszystko jest lepsze z SIMD):
Dużą zaletą tej implementacji jest to, że można ją łatwo dostosować do wykonywania 4 równoległych multiplikacji bez
*
lub w+
razie potrzeby.źródło
źródło
strlen(cg) != a
jest bardzo trollingową metodą eliminacji--
(czyni to O (N * N)).Prawdopodobnie za szybko :-(
źródło
Ta wersja Haskell działa tylko z nieujemnymi liczbami całkowitymi, ale dokonuje mnożenia w sposób, w jaki dzieci uczą się tego po raz pierwszy. Tj. 3x4 to 3 grupy po 4 rzeczy. W tym przypadku liczone „rzeczy” to wycięcia („|”) na patyku.
źródło
Może to działać w C99, jeśli pogoda jest odpowiednia, a Twój kompilator obsługuje niezdefiniowane bzdury.
źródło
Ponieważ OP nie poprosił o C , oto jeden w (Oracle) SQL!
źródło
*
s!Może zawierać śladowe ilości UD.
źródło
Testowe uruchomienie:
źródło