Wie würden Sie eine Reihe von 3 teilen , ohne *
, /
, +
, -
, %
, Betreiber?
Die Nummer kann signiert oder nicht signiert sein.
Wie würden Sie eine Reihe von 3 teilen , ohne *
, /
, +
, -
, %
, Betreiber?
Die Nummer kann signiert oder nicht signiert sein.
Antworten:
Dies ist eine einfache Funktion, die die gewünschte Operation ausführt. Da jedoch der +
Operator erforderlich ist , müssen Sie nur noch die Werte mit Bitoperatoren hinzufügen:
// replaces the + operator
int add(int x, int y)
{
while (x) {
int t = (x & y) << 1;
y ^= x;
x = t;
}
return y;
}
int divideby3(int num)
{
int sum = 0;
while (num > 3) {
sum = add(num >> 2, sum);
num = add(num >> 2, num & 3);
}
if (num == 3)
sum = add(sum, 1);
return sum;
}
Wie Jim kommentierte, funktioniert dies, weil:
n = 4 * a + b
n / 3 = a + (a + b) / 3
So sum += a
, n = a + b
und iterate
Wenn a == 0 (n < 4)
, sum += floor(n / 3);
dh 1,if n == 3, else 0
1 / 3 = 0.333333
Die sich wiederholenden Zahlen erleichtern die Berechnung mit a / 3 = a/10*3 + a/100*3 + a/1000*3 + (..)
. In der Binärdatei ist es fast dasselbe: 1 / 3 = 0.0101010101 (base 2)
was dazu führt a / 3 = a/4 + a/16 + a/64 + (..)
. Durch Teilen durch 4 kommt die Bitverschiebung. Die letzte Überprüfung von num == 3 ist erforderlich, da wir nur Ganzzahlen haben, mit denen wir arbeiten können.
a / 3 = a * 0.111111 (base 4) = a * 4^-1 + a * 4^-2 + a * 4^-3 + (..) = a >> 2 + a >> 4 + a >> 6 + (..)
. Die Basis 4 erklärt auch, warum am Ende nur 3 aufgerundet wird, während 1 und 2 abgerundet werden können.
n == 2^k
Folgendes gilt : x % n == x & (n-1)
, wird hier num & 3
also verwendet, um auszuführen, num % 4
solange dies %
nicht erlaubt ist.
Idiotische Bedingungen erfordern eine idiotische Lösung:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE * fp=fopen("temp.dat","w+b");
int number=12346;
int divisor=3;
char * buf = calloc(number,1);
fwrite(buf,number,1,fp);
rewind(fp);
int result=fread(buf,divisor,number,fp);
printf("%d / %d = %d", number, divisor, result);
free(buf);
fclose(fp);
return 0;
}
Wenn auch der Dezimalteil benötigt wird, deklarieren Sie einfach result
als double
und fügen Sie das Ergebnis von hinzu fmod(number,divisor)
.
Erklärung, wie es funktioniert
fwrite
Schreibvorgänge number
Bytes (Zahl ist 123456 in dem obigen Beispiel).rewind
Setzt den Dateizeiger auf die Vorderseite der Datei zurück.fread
liest maximal number
"Datensätze" divisor
mit einer Länge aus der Datei und gibt die Anzahl der gelesenen Elemente zurück.Wenn Sie 30 Bytes schreiben und dann die Datei in Einheiten von 3 zurücklesen, erhalten Sie 10 "Einheiten". 30/3 = 10
log(pow(exp(number),0.33333333333333333333)) /* :-) */
Math.log(Math.pow(Math.exp(709),0.33333333333333333333))
undMath.log(Math.pow(Math.exp(709),Math.sin(Math.atan2(1,Math.sqrt(8)))))
Sie können (plattformabhängige) Inline-Assembly verwenden, z. B. für x86: (funktioniert auch für negative Zahlen)
#include <stdio.h>
int main() {
int dividend = -42, divisor = 5, quotient, remainder;
__asm__ ( "cdq; idivl %%ebx;"
: "=a" (quotient), "=d" (remainder)
: "a" (dividend), "b" (divisor)
: );
printf("%i / %i = %i, remainder: %i\n", dividend, divisor, quotient, remainder);
return 0;
}
asm
Direktive ist. Und ich würde hinzufügen, dass C-Compiler nicht die einzigen sind, die Inline-Assembler haben, Delphi hat das auch.
asm
Richtlinie wird nur in der Norm C99 unter Anhang J - Allgemeine Erweiterungen erwähnt.
Verwenden Sie itoa , um eine Basis-3-Zeichenfolge zu konvertieren. Lass den letzten Trit fallen und konvertiere zurück zu Basis 10.
// Note: itoa is non-standard but actual implementations
// don't seem to handle negative when base != 10.
int div3(int i) {
char str[42];
sprintf(str, "%d", INT_MIN); // Put minus sign at str[0]
if (i>0) // Remove sign if positive
str[0] = ' ';
itoa(abs(i), &str[1], 3); // Put ternary absolute value starting at str[1]
str[strlen(&str[1])] = '\0'; // Drop last digit
return strtol(str, NULL, 3); // Read back result
}
itoa
das eine beliebige Basis verwenden könnte. Wenn Sie eine vollständige funktionierende Implementierung mit durchführen, itoa
werde ich abstimmen.
/
und %
... :-)
printf
zur Anzeige Ihres Dezimalergebnisses.
(Hinweis: Eine bessere Version finden Sie unter Bearbeiten 2 unten!)
Dies ist nicht so schwierig, wie es sich anhört, weil Sie "ohne Verwendung der Operatoren [..] +
[..] " gesagt haben . Siehe unten, wenn Sie die Verwendung des Charakters insgesamt verbieten möchten .+
unsigned div_by(unsigned const x, unsigned const by) {
unsigned floor = 0;
for (unsigned cmp = 0, r = 0; cmp <= x;) {
for (unsigned i = 0; i < by; i++)
cmp++; // that's not the + operator!
floor = r;
r++; // neither is this.
}
return floor;
}
dann nur sagen , div_by(100,3)
zu dividieren 100
durch 3
.
++
Operator auch ersetzen :unsigned inc(unsigned x) {
for (unsigned mask = 1; mask; mask <<= 1) {
if (mask & x)
x &= ~mask;
else
return x & mask;
}
return 0; // overflow (note that both x and mask are 0 here)
}
+
, -
, *
, /
, %
Zeichen .unsigned add(char const zero[], unsigned const x, unsigned const y) {
// this exploits that &foo[bar] == foo+bar if foo is of type char*
return (int)(uintptr_t)(&((&zero[x])[y]));
}
unsigned div_by(unsigned const x, unsigned const by) {
unsigned floor = 0;
for (unsigned cmp = 0, r = 0; cmp <= x;) {
cmp = add(0,cmp,by);
floor = r;
r = add(0,r,1);
}
return floor;
}
Wir verwenden das erste Argument der add
Funktion, da wir den Zeigertyp ohne Verwendung des *
Zeichens nicht bezeichnen können , außer in Funktionsparameterlisten, in denen die Syntax type[]
identisch ist mit type* const
.
FWIW, Sie können eine Multiplikationsfunktion einfach mit einem ähnlichen Trick implementieren, um den 0x55555556
von AndreyT vorgeschlagenen Trick zu verwenden :
int mul(int const x, int const y) {
return sizeof(struct {
char const ignore[y];
}[x]);
}
++
: Warum verwenden Sie nicht einfach /=
?
++
ist auch eine Abkürzung: Für num = num + 1
.
+=
ist endlich eine Abkürzung für num = num + 1
.
Auf dem Setun-Computer ist dies problemlos möglich .
Um eine ganze Zahl durch 3 zu teilen, verschieben Sie sie um 1 Stelle nach rechts .
Ich bin mir nicht sicher, ob es durchaus möglich ist, einen konformen C-Compiler auf einer solchen Plattform zu implementieren. Möglicherweise müssen wir die Regeln etwas erweitern, z. B. "mindestens 8 Bits" als "in der Lage, mindestens ganze Zahlen von -128 bis +127 zu halten" interpretieren.
>>
Operator ist der Operator "Division durch 2 ^ n", dh er wird in Bezug auf die Arithmetik und nicht in Bezug auf die Maschinendarstellung angegeben.
Wie wäre es mit einer Nachschlagetabelle mit vorberechneten Antworten, da es von Oracle stammt? :-D
Hier ist meine Lösung:
public static int div_by_3(long a) {
a <<= 30;
for(int i = 2; i <= 32 ; i <<= 1) {
a = add(a, a >> i);
}
return (int) (a >> 32);
}
public static long add(long a, long b) {
long carry = (a & b) << 1;
long sum = (a ^ b);
return carry == 0 ? sum : add(carry, sum);
}
Beachten Sie zunächst, dass
1/3 = 1/4 + 1/16 + 1/64 + ...
Jetzt ist der Rest einfach!
a/3 = a * 1/3
a/3 = a * (1/4 + 1/16 + 1/64 + ...)
a/3 = a/4 + a/16 + 1/64 + ...
a/3 = a >> 2 + a >> 4 + a >> 6 + ...
Jetzt müssen wir nur noch diese bitverschobenen Werte von a addieren! Hoppla! Wir können jedoch nicht hinzufügen, daher müssen wir stattdessen eine Add-Funktion mit bitweisen Operatoren schreiben! Wenn Sie mit bitweisen Operatoren vertraut sind, sollte meine Lösung ziemlich einfach aussehen ... aber falls Sie dies nicht tun, werde ich am Ende ein Beispiel durchgehen.
Eine andere Sache zu beachten ist, dass ich zuerst um 30 nach links verschiebe! Dies soll sicherstellen, dass die Brüche nicht abgerundet werden.
11 + 6
1011 + 0110
sum = 1011 ^ 0110 = 1101
carry = (1011 & 0110) << 1 = 0010 << 1 = 0100
Now you recurse!
1101 + 0100
sum = 1101 ^ 0100 = 1001
carry = (1101 & 0100) << 1 = 0100 << 1 = 1000
Again!
1001 + 1000
sum = 1001 ^ 1000 = 0001
carry = (1001 & 1000) << 1 = 1000 << 1 = 10000
One last time!
0001 + 10000
sum = 0001 ^ 10000 = 10001 = 17
carry = (0001 & 10000) << 1 = 0
Done!
Es ist einfach eine Ergänzung, die Sie als Kind gelernt haben!
111
1011
+0110
-----
10001
Diese Implementierung ist fehlgeschlagen, da nicht alle Begriffe der Gleichung hinzugefügt werden können:
a / 3 = a/4 + a/4^2 + a/4^3 + ... + a/4^i + ... = f(a, i) + a * 1/3 * 1/4^i
f(a, i) = a/4 + a/4^2 + ... + a/4^i
Angenommen, die Auflösung von div_by_3(a)
= x ist dann x <= floor(f(a, i)) < a / 3
. Wann a = 3k
bekommen wir eine falsche Antwort.
n/3
ist immer kleiner als, n/3
was bedeutet, dass für jedes n=3k
Ergebnis k-1
stattdessen wäre k
.
Um eine 32-Bit-Zahl durch 3 zu teilen, kann man sie mit multiplizieren 0x55555556
und dann die oberen 32 Bits des 64-Bit-Ergebnisses nehmen.
Jetzt müssen Sie nur noch die Multiplikation mit Bitoperationen und Verschiebungen implementieren ...
multiply it
. Würde das nicht bedeuten, den verbotenen *
Operator zu verwenden?
Noch eine andere Lösung. Dies sollte alle Ints (einschließlich negativer Ints) mit Ausnahme des Min-Werts eines Int behandeln, der als fest codierte Ausnahme behandelt werden müsste. Dies erfolgt grundsätzlich durch Subtraktion, jedoch nur unter Verwendung von Bitoperatoren (Verschiebungen, xor & und Komplement). Für eine schnellere Geschwindigkeit subtrahiert es 3 * (abnehmende Potenzen von 2). In c # werden ungefähr 444 dieser DivideBy3-Aufrufe pro Millisekunde ausgeführt (2,2 Sekunden für 1.000.000 Teilungen), also nicht schrecklich langsam, aber nicht annähernd so schnell wie ein einfaches x / 3. Im Vergleich dazu ist Coodeys nette Lösung ungefähr fünfmal schneller als diese.
public static int DivideBy3(int a) {
bool negative = a < 0;
if (negative) a = Negate(a);
int result;
int sub = 3 << 29;
int threes = 1 << 29;
result = 0;
while (threes > 0) {
if (a >= sub) {
a = Add(a, Negate(sub));
result = Add(result, threes);
}
sub >>= 1;
threes >>= 1;
}
if (negative) result = Negate(result);
return result;
}
public static int Negate(int a) {
return Add(~a, 1);
}
public static int Add(int a, int b) {
int x = 0;
x = a ^ b;
while ((a & b) != 0) {
b = (a & b) << 1;
a = x;
x = a ^ b;
}
return x;
}
Dies ist c #, weil ich das zur Hand hatte, aber die Unterschiede zu c sollten gering sein.
(a >= sub)
als Subtraktion?
Es ist wirklich ganz einfach.
if (number == 0) return 0;
if (number == 1) return 0;
if (number == 2) return 0;
if (number == 3) return 1;
if (number == 4) return 1;
if (number == 5) return 1;
if (number == 6) return 2;
(Ich habe der Kürze halber natürlich einen Teil des Programms weggelassen.) Wenn der Programmierer es satt hat, dies alles abzutippen, bin ich sicher, dass er oder sie ein separates Programm schreiben könnte, um es für ihn zu generieren. Mir ist zufällig ein bestimmter Bediener bekannt, der /
seine Arbeit immens vereinfachen würde.
Dictionary<number, number>
anstelle von wiederholten if
Anweisungen eine verwenden, um O(1)
zeitliche Komplexität zu erzielen!
Die Verwendung von Zählern ist eine grundlegende Lösung:
int DivBy3(int num) {
int result = 0;
int counter = 0;
while (1) {
if (num == counter) //Modulus 0
return result;
counter = abs(~counter); //++counter
if (num == counter) //Modulus 1
return result;
counter = abs(~counter); //++counter
if (num == counter) //Modulus 2
return result;
counter = abs(~counter); //++counter
result = abs(~result); //++result
}
}
Es ist auch einfach, eine Modulfunktion auszuführen, überprüfen Sie die Kommentare.
Dies ist der klassische Divisionsalgorithmus in Basis 2:
#include <stdio.h>
#include <stdint.h>
int main()
{
uint32_t mod3[6] = { 0,1,2,0,1,2 };
uint32_t x = 1234567; // number to divide, and remainder at the end
uint32_t y = 0; // result
int bit = 31; // current bit
printf("X=%u X/3=%u\n",x,x/3); // the '/3' is for testing
while (bit>0)
{
printf("BIT=%d X=%u Y=%u\n",bit,x,y);
// decrement bit
int h = 1; while (1) { bit ^= h; if ( bit&h ) h <<= 1; else break; }
uint32_t r = x>>bit; // current remainder in 0..5
x ^= r<<bit; // remove R bits from X
if (r >= 3) y |= 1<<bit; // new output bit
x |= mod3[r]<<bit; // new remainder inserted in X
}
printf("Y=%u\n",y);
}
Schreiben Sie das Programm in Pascal und verwenden Sie den DIV
Operator.
Da ist die Frage markiert ckönnen Sie wahrscheinlich eine Funktion in Pascal schreiben und von Ihrem C-Programm aus aufrufen; Die Methode hierfür ist systemspezifisch.
Aber hier ist ein Beispiel, das auf meinem Ubuntu-System mit dem fp-compiler
installierten Free Pascal- Paket funktioniert . (Ich mache das aus purer Sturheit; ich behaupte nicht, dass dies nützlich ist.)
divide_by_3.pas
::
unit Divide_By_3;
interface
function div_by_3(n: integer): integer; cdecl; export;
implementation
function div_by_3(n: integer): integer; cdecl;
begin
div_by_3 := n div 3;
end;
end.
main.c
::
#include <stdio.h>
#include <stdlib.h>
extern int div_by_3(int n);
int main(void) {
int n;
fputs("Enter a number: ", stdout);
fflush(stdout);
scanf("%d", &n);
printf("%d / 3 = %d\n", n, div_by_3(n));
return 0;
}
Bauen:
fpc divide_by_3.pas && gcc divide_by_3.o main.c -o main
Beispielausführung:
$ ./main
Enter a number: 100
100 / 3 = 33
int div3(int x)
{
int reminder = abs(x);
int result = 0;
while(reminder >= 3)
{
result++;
reminder--;
reminder--;
reminder--;
}
return result;
}
ADD
und INC
dass sie nicht gleiche Opcodes haben.
Es wurde nicht überprüft, ob diese Antwort bereits veröffentlicht wurde. Wenn das Programm auf Gleitkommazahlen erweitert werden muss, können die Zahlen mit der erforderlichen Genauigkeit von 10 * multipliziert werden, und dann kann der folgende Code erneut angewendet werden.
#include <stdio.h>
int main()
{
int aNumber = 500;
int gResult = 0;
int aLoop = 0;
int i = 0;
for(i = 0; i < aNumber; i++)
{
if(aLoop == 3)
{
gResult++;
aLoop = 0;
}
aLoop++;
}
printf("Reulst of %d / 3 = %d", aNumber, gResult);
return 0;
}
Dies sollte für jeden Divisor funktionieren, nicht nur für drei. Derzeit nur für nicht signierte, aber die Erweiterung auf signierte sollte nicht so schwierig sein.
#include <stdio.h>
unsigned sub(unsigned two, unsigned one);
unsigned bitdiv(unsigned top, unsigned bot);
unsigned sub(unsigned two, unsigned one)
{
unsigned bor;
bor = one;
do {
one = ~two & bor;
two ^= bor;
bor = one<<1;
} while (one);
return two;
}
unsigned bitdiv(unsigned top, unsigned bot)
{
unsigned result, shift;
if (!bot || top < bot) return 0;
for(shift=1;top >= (bot<<=1); shift++) {;}
bot >>= 1;
for (result=0; shift--; bot >>= 1 ) {
result <<=1;
if (top >= bot) {
top = sub(top,bot);
result |= 1;
}
}
return result;
}
int main(void)
{
unsigned arg,val;
for (arg=2; arg < 40; arg++) {
val = bitdiv(arg,3);
printf("Arg=%u Val=%u\n", arg, val);
}
return 0;
}
Wäre es ein Betrug, den /
Operator "hinter den Kulissen" mithilfe von eval
String-Verkettung zu verwenden?
In Javacript können Sie dies beispielsweise tun
function div3 (n) {
var div = String.fromCharCode(47);
return eval([n, div, 3].join(""));
}
Verwenden von BC Math in PHP :
<?php
$a = 12345;
$b = bcdiv($a, 3);
?>
MySQL (es ist ein Interview von Oracle)
> SELECT 12345 DIV 3;
Pascal :
a:= 12345;
b:= a div 3;
x86-64 Assemblersprache:
mov r8, 3
xor rdx, rdx
mov rax, 12345
idiv r8
Zuerst habe ich mir etwas ausgedacht.
irb(main):101:0> div3 = -> n { s = '%0' + n.to_s + 's'; (s % '').gsub(' ', ' ').size }
=> #<Proc:0x0000000205ae90@(irb):101 (lambda)>
irb(main):102:0> div3[12]
=> 4
irb(main):103:0> div3[666]
=> 222
EDIT: Sorry, ich habe das Tag nicht bemerkt C
. Aber Sie können die Idee der String-Formatierung verwenden, denke ich ...
Das folgende Skript generiert ein C-Programm, das das Problem ohne Verwendung der Operatoren löst * / + - %
:
#!/usr/bin/env python3
print('''#include <stdint.h>
#include <stdio.h>
const int32_t div_by_3(const int32_t input)
{
''')
for i in range(-2**31, 2**31):
print(' if(input == %d) return %d;' % (i, i / 3))
print(r'''
return 42; // impossible
}
int main()
{
const int32_t number = 8;
printf("%d / 3 = %d\n", number, div_by_3(number));
}
''')
Verwenden des Hacker Delight Magic Zahlenrechners
int divideByThree(int num)
{
return (fma(num, 1431655766, 0) >> 32);
}
Wobei fma eine im math.h
Header definierte Standardbibliotheksfunktion ist .
-
weder den noch den *
Operator?
Wie wäre es mit diesem Ansatz (c #)?
private int dividedBy3(int n) {
List<Object> a = new Object[n].ToList();
List<Object> b = new List<object>();
while (a.Count > 2) {
a.RemoveRange(0, 3);
b.Add(new Object());
}
return b.Count;
}
Ich denke die richtige Antwort ist:
Warum sollte ich keinen Basisoperator verwenden, um eine Basisoperation auszuführen?
Die Lösung mit der Bibliotheksfunktion fma () funktioniert für jede positive Zahl:
#include <stdio.h>
#include <math.h>
int main()
{
int number = 8;//Any +ve no.
int temp = 3, result = 0;
while(temp <= number){
temp = fma(temp, 1, 3); //fma(a, b, c) is a library function and returns (a*b) + c.
result = fma(result, 1, 1);
}
printf("\n\n%d divided by 3 = %d\n", number, result);
}
Verwenden Sie cblas , die Teil des Accelerate-Frameworks von OS X sind.
[02:31:59] [william@relativity ~]$ cat div3.c
#import <stdio.h>
#import <Accelerate/Accelerate.h>
int main() {
float multiplicand = 123456.0;
float multiplier = 0.333333;
printf("%f * %f == ", multiplicand, multiplier);
cblas_sscal(1, multiplier, &multiplicand, 1);
printf("%f\n", multiplicand);
}
[02:32:07] [william@relativity ~]$ clang div3.c -framework Accelerate -o div3 && ./div3
123456.000000 * 0.333333 == 41151.957031
Zuerst:
x/3 = (x/4) / (1-1/4)
Dann finde heraus, wie man x / (1 - y) löst:
x/(1-1/y)
= x * (1+y) / (1-y^2)
= x * (1+y) * (1+y^2) / (1-y^4)
= ...
= x * (1+y) * (1+y^2) * (1+y^4) * ... * (1+y^(2^i)) / (1-y^(2^(i+i))
= x * (1+y) * (1+y^2) * (1+y^4) * ... * (1+y^(2^i))
mit y = 1/4:
int div3(int x) {
x <<= 6; // need more precise
x += x>>2; // x = x * (1+(1/2)^2)
x += x>>4; // x = x * (1+(1/2)^4)
x += x>>8; // x = x * (1+(1/2)^8)
x += x>>16; // x = x * (1+(1/2)^16)
return (x+1)>>8; // as (1-(1/2)^32) very near 1,
// we plus 1 instead of div (1-(1/2)^32)
}
Es wird zwar verwendet +
, aber jemand implementiert bereits add by bitwise op.