Nasıl kullanmadan 3 bir numara bölmek istiyorum *
, /
, +
, -
, %
, operatörler?
Numara imzalanmış veya imzalanmamış olabilir.
Nasıl kullanmadan 3 bir numara bölmek istiyorum *
, /
, +
, -
, %
, operatörler?
Numara imzalanmış veya imzalanmamış olabilir.
Yanıtlar:
Bu, istenen işlemi gerçekleştiren basit bir işlevdir . Ancak +
işleç gerektirir , bu yüzden tek yapmanız gereken değerleri bit işleçleriyle eklemektir:
// 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;
}
Jim'in yorumladığı gibi, çünkü:
n = 4 * a + b
n / 3 = a + (a + b) / 3
Yani sum += a
, n = a + b
ve tekrar
Ne zaman a == 0 (n < 4)
, sum += floor(n / 3);
yani 1,if n == 3, else 0
1 / 3 = 0.333333
yinelenen sayılar bunu kullanarak hesaplamayı kolaylaştırır a / 3 = a/10*3 + a/100*3 + a/1000*3 + (..)
. İkili dosyada neredeyse aynı: 1 / 3 = 0.0101010101 (base 2)
yol açar a / 3 = a/4 + a/16 + a/64 + (..)
. 4'e bölmek bit kaydırmanın geldiği yerdir. Num == 3 üzerinde son kontrol gerekli çünkü sadece üzerinde çalışacak tamsayılarımız var.
a / 3 = a * 0.111111 (base 4) = a * 4^-1 + a * 4^-2 + a * 4^-3 + (..) = a >> 2 + a >> 4 + a >> 6 + (..)
. Taban 4 ayrıca sonunda sadece 3'ün neden yuvarlanırken 1 ve 2'nin yuvarlanabileceğini açıklar.
n == 2^k
: Aşağıdaki doğrudur x % n == x & (n-1)
, bu yüzden burada num & 3
gerçekleştirmek için kullanılır num % 4
iken %
izin verilmez.
İdiyotik koşullar aptalca bir çözüm gerektirir:
#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;
}
Ondalık kısmı tabi de, sadece beyan result
olarak double
ve buna sonucunu ekleyin fmod(number,divisor)
.
Nasıl çalıştığının açıklaması
fwrite
yazıyornumber
bayt (sayısı, örneğin yukarıda 123456 olmak üzere).rewind
dosya işaretçisini dosyanın önüne sıfırlar.fread
dosyadan en fazla sayıda number
"kayıt" okur divisor
ve okuduğu öğelerin sayısını döndürür.30 bayt yazarsanız ve dosyayı 3 birim halinde tekrar okursanız, 10 "birim" elde edersiniz. 30/3 = 10
log(pow(exp(number),0.33333333333333333333)) /* :-) */
Math.log(Math.pow(Math.exp(709),0.33333333333333333333))
veMath.log(Math.pow(Math.exp(709),Math.sin(Math.atan2(1,Math.sqrt(8)))))
(Platforma bağlı) satır içi montajı kullanabilirsiniz, örneğin, x86 için: (ayrıca negatif sayılar için de çalışır)
#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
direktif. Ve C derleyicilerinin satır içi montajcıları olan tek kişi olmadığını ekleyeceğim, Delphi'de de var.
asm
Yönerge yalnızca Ek J - ortak uzantılar altındaki C99 standardında belirtilmiştir.
Temel 3 dizeye dönüştürmek için itoa kullanın . Son triti bırakın ve tabana 10 dönün.
// 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
keyfi bir taban kullanabileceğini bilmiyordum . Kullanarak tam bir çalışma uygulaması itoa
yaparsanız oyları kaldırırım.
/
ve %
... :-)
printf
Ondalık sonucunuzu görüntülemek için uygulanması da öyle .
(not: daha iyi bir sürüm için aşağıdaki Düzen 2'ye bakın!)
Bu, göründüğü kadar zor değil, çünkü "[..] +
[..] operatörlerini kullanmadan" dediniz . +
Karakterin birlikte kullanılmasını yasaklamak istiyorsanız aşağıya bakın .
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;
}
Sonra sadece söylemek div_by(100,3)
bölünmeden 100
tarafından 3
.
++
Operatöre devam edebilir ve değiştirebilirsiniz :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)
}
+
, -
, *
, /
, %
karakterleri .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;
}
add
İşlevin ilk bağımsız değişkenini kullanırız, çünkü *
sözdiziminin type[]
özdeş olduğu işlev parametre listeleri hariç , karakteri kullanmadan işaretçi türlerini gösteremeyiz type* const
.
FWIW, AndreyT0x55555556
tarafından önerilen hileyi kullanmak için benzer bir hile kullanarak kolayca bir çarpma işlevi uygulayabilirsiniz :
int mul(int const x, int const y) {
return sizeof(struct {
char const ignore[y];
}[x]);
}
++
: Neden sadece kullanmıyorsunuz /=
?
++
aynı zamanda bir kısayoldur: İçin num = num + 1
.
+=
sonunda bir kısayol num = num + 1
.
Setun bilgisayarında kolayca mümkündür .
Bir tamsayıyı 3'e bölmek için sağa 1 yer kaydırın .
Böyle bir platforma uygun bir C derleyicisi uygulamak kesinlikle mümkün olup olmadığından emin değilim. "En az 8 bit" i "-128 ile +127 arasında en az tamsayı tutabilen" olarak yorumlamak gibi kuralları biraz uzatmamız gerekebilir.
>>
İşleç, "2 ^ n'ye bölünme" operatörüdür, yani makine temsili değil aritmetik olarak belirtilir.
Oracle'dan beri, önceden hesaplanmış cevapların bir arama tablosuna ne dersiniz? :-D
İşte benim çözümüm:
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);
}
İlk olarak,
1/3 = 1/4 + 1/16 + 1/64 + ...
Şimdi, gerisi basit!
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 + ...
Şimdi tek yapmamız gereken bu! Hata! Yine de ekleyemeyiz, bunun yerine bit bilge operatörleri kullanarak bir ekleme işlevi yazmamız gerekecek! Bit bilge operatörlere aşina iseniz, çözümüm oldukça basit görünmelidir ... ancak sadece olmamanız durumunda, sonunda bir örnek üzerinde duracağım.
Dikkat edilmesi gereken başka bir şey, önce 30'a sola kaydırmam! Bu, kesirlerin yuvarlanmadığından emin olmak içindir.
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!
Çocukken öğrendiğiniz bir ek taşıma!
111
1011
+0110
-----
10001
Denklemin tüm terimlerini ekleyemediğimiz için bu uygulama başarısız oldu :
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
div_by_3(a)
= X sonucunun yeniden alındığını varsayalım x <= floor(f(a, i)) < a / 3
. Ne zaman a = 3k
, yanlış cevap alırız.
n/3
her zamankinden daha azdır n/3
; bu n=3k
, sonuç k-1
yerine herhangi bir sonuç için olacağı anlamına gelir k
.
32 bitlik bir sayıyı 3'e bölmek için, sayı ile çarpılabilir 0x55555556
ve sonra 64 bitlik sonucun üst 32 bitini alabilir.
Şimdi tek yapmanız gereken bit işlemleri ve vardiyaları kullanarak çarpmayı uygulamak ...
multiply it
. Bu yasak *
operatörü kullanmak anlamına gelmez mi ?
Yine başka bir çözüm. Bu, sabit kodlanmış bir istisna olarak ele alınması gereken bir int değerinin min değeri hariç tüm girişleri (negatif girişler dahil) ele almalıdır. Bu temelde çıkarma yoluyla bölme yapar, ancak sadece bit işleçleri (vardiya, xor ve ve tamamlayıcı) kullanır. Daha yüksek hız için 3 * çıkarır (2'nin azalan gücü). C # 'da, milisaniye başına bu DivideBy3 çağrılarının yaklaşık 444'ünü (1.000.000 bölme için 2.2 saniye) yürütür, bu yüzden korkunç derecede yavaş değildir, ancak basit bir x / 3 kadar hızlı bir yerde yoktur. Karşılaştırıldığında, Coodey'in güzel çözümü bundan 5 kat daha hızlıdır.
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;
}
Bu c # çünkü ben kullanışlı vardı, ama c farklılıkları küçük olmalıdır.
(a >= sub)
Çıkarma sayılır mı ?
Gerçekten çok kolay.
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;
(Elbette kısalık uğruna programın bir kısmını atladım.) Programcı hepsini yazmaktan yorulursa, onu kendisi için oluşturmak için ayrı bir program yazabileceğinden eminim. Belirli bir operatörün farkındayım /
, bu da işini son derece basitleştirecek.
Dictionary<number, number>
tekrarlanan if
ifadeler yerine kullanabilirsiniz O(1)
!
Sayaçları kullanmak temel bir çözümdür:
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
}
}
Ayrıca bir modül işlevi gerçekleştirmek kolaydır, yorumları kontrol edin.
Bu, taban 2'deki klasik bölüm algoritmasıdır:
#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);
}
Programı Pascal'a yazın ve DIV
operatörü kullanın .
Soru etiketlendiğinden c, Pascal'da bir işlev yazabilir ve C programınızdan çağırabilirsiniz; bunu yapmanın yöntemi sisteme özgüdür.
Ancak, Free Pascal fp-compiler
paketi kurulu olarak Ubuntu sistemimde çalışan bir örnek . (Bunu yanlış yerleştirilmiş inatçılıktan yapıyorum; bunun yararlı olduğunu iddia etmiyorum.)
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;
}
İnşa etmek:
fpc divide_by_3.pas && gcc divide_by_3.o main.c -o main
Örnek yürütme:
$ ./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
ve INC
bunların aynı opcode sahip olmamaları.
Bu cevabın zaten yayınlanıp yayınlanmadığını kontrol etmedi. Programın kayan sayılara genişletilmesi gerekiyorsa, sayılar gereken hassasiyet sayısı 10 * ile çarpılabilir ve ardından aşağıdaki kod tekrar uygulanabilir.
#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;
}
Bu sadece üç değil, herhangi bir bölen için işe yarayacaktır. Şu anda sadece imzasız, ancak imzalı olarak genişletmek o kadar zor olmamalı.
#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;
}
/
"String'in arkasında" operatörünü eval
ve string bitiştirmeyi kullanarak kullanmak hile olur mu?
Örneğin, Javacript'te şunları yapabilirsiniz:
function div3 (n) {
var div = String.fromCharCode(47);
return eval([n, div, 3].join(""));
}
Kullanılması M.Ö. Matematik içinde PHP :
<?php
$a = 12345;
$b = bcdiv($a, 3);
?>
MySQL (Oracle'dan bir röportaj)
> SELECT 12345 DIV 3;
Pascal :
a:= 12345;
b:= a div 3;
x86-64 montaj dili:
mov r8, 3
xor rdx, rdx
mov rax, 12345
idiv r8
Önce ben geldim.
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: Üzgünüm, etiketi fark etmedim C
. Ama dize biçimlendirme fikrini kullanabilirsiniz sanırım ...
Aşağıdaki komut dosyası, işleçleri kullanmadan sorunu çözen bir C programı oluşturur * / + - %
:
#!/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));
}
''')
Kullanılması Hacker'ın Delight Sihirli sayı hesap makinesi
int divideByThree(int num)
{
return (fma(num, 1431655766, 0) >> 32);
}
Burada fma , math.h
başlıkta tanımlanan standart bir kütüphane fonksiyonudur .
-
ne *
operatörü ne de kullanmıyor ?
Bu yaklaşıma ne dersiniz (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;
}
Bence doğru cevap:
Temel bir işlemi yapmak için neden temel bir operatör kullanmıyorum?
Fma () kitaplık işlevini kullanan çözüm , herhangi bir pozitif sayı için çalışır:
#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);
}
OS X'in Accelerate çerçevesinin bir parçası olarak dahil edilen cblas'ı kullanın .
[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
İlk:
x/3 = (x/4) / (1-1/4)
Sonra x / (1 - y) 'nin nasıl çözüleceğini öğrenin:
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))
y = 1/4 ile:
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)
}
Her ne kadar kullansa da +
, birileri zaten uygular bitwise op tarafından ekleyin.