어떻게 사용하지 않고 3으로 번호를 나누는 것 *
, /
, +
, -
, %
, 연산자?
숫자는 부호가 있거나 부호가 없을 수 있습니다.
어떻게 사용하지 않고 3으로 번호를 나누는 것 *
, /
, +
, -
, %
, 연산자?
숫자는 부호가 있거나 부호가 없을 수 있습니다.
답변:
원하는 작업을 수행 하는 간단한 기능 입니다. 그러나 +
연산자 가 필요 하므로 비트 연산자로 값을 추가하기 만하면됩니다.
// 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은 다음과 같은 이유로이 작업을 설명했습니다.
n = 4 * a + b
n / 3 = a + (a + b) / 3
그래서 sum += a
, n = a + b
그리고 반복
언제 a == 0 (n < 4)
, sum += floor(n / 3);
즉 1,if n == 3, else 0
1 / 3 = 0.333333
에서 반복되는 숫자는을 사용하여 쉽게 계산할 수 a / 3 = a/10*3 + a/100*3 + a/1000*3 + (..)
있습니다. 바이너리에서 거의 동일합니다 : 1 / 3 = 0.0101010101 (base 2)
에있는 리드 a / 3 = a/4 + a/16 + a/64 + (..)
. 4로 나누면 비트 시프트가 시작됩니다. 우리는 정수만 가지고 있기 때문에 num == 3에 대한 마지막 점검이 필요합니다.
a / 3 = a * 0.111111 (base 4) = a * 4^-1 + a * 4^-2 + a * 4^-3 + (..) = a >> 2 + a >> 4 + a >> 6 + (..)
집니다.. 밑면 4는 왜 끝에 3 만 반올림하는지 설명하고 1과 2는 반올림 할 수 있습니다.
n == 2^k
다음과 같은 경우에 해당합니다. x % n == x & (n-1)
따라서 허용되지 않는 동안 여기 num & 3
에서 수행 num % 4
하는 데 사용됩니다 %
.
이디 오 상태는 이디 오 솔루션을 요구합니다.
#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;
}
소수 부분이 필요 또한, 그냥 선언 result
으로 double
하고 여기에 결과를 추가합니다 fmod(number,divisor)
.
작동 방식에 대한 설명
fwrite
쓰기 용 number
바이트 (숫자는 상기 예에서 123456이다).rewind
파일 포인터를 파일 앞쪽으로 재설정합니다.fread
파일에서 길이 number
가 최대 인 "레코드"를 divisor
읽고 읽은 요소 수를 반환합니다.30 바이트를 쓴 다음 3 단위로 파일을 다시 읽으면 10 개의 "단위"가 표시됩니다. 30/3 = 10
log(pow(exp(number),0.33333333333333333333)) /* :-) */
Math.log(Math.pow(Math.exp(709),0.33333333333333333333))
와 작동하지 않습니다.Math.log(Math.pow(Math.exp(709),Math.sin(Math.atan2(1,Math.sqrt(8)))))
예를 들어 x86의 경우 (플랫폼 종속) 인라인 어셈블리를 사용할 수 있습니다. (음수에도 적용됨)
#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
지시어는 사실 입니다. 그리고 C 컴파일러는 인라인 어셈블러가있는 유일한 컴파일러가 아니라고 델파이도 마찬가지입니다.
asm
지시문은 부록 J-공통 확장명 아래 C99 표준에만 언급되어 있습니다.
itoa 를 사용하여 밑줄 3 문자열로 변환 하십시오 . 마지막 trit를 버리고 base 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
임의의 기초를 사용할 수 있다는 것을 몰랐습니다 . 당신이 사용하여 완전한 작업 구현을 수행한다면 itoa
나는 공감할 것이다.
/
과 같습니다. %
... :-)
printf
십진 결과 표시 를 위한 구현도 마찬가지 입니다.
(참고 : 더 나은 버전을 보려면 아래 편집 2를 참조하십시오!)
"[..] +
[..] 연산자 를 사용하지 않고"라고 말했기 때문에이 방법은 까다 롭지 않습니다 . +
문자를 함께 사용하는 것을 금지하려면 아래를 참조하십시오 .
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;
}
그럼 그냥 말을 div_by(100,3)
나누기에 100
의해 3
.
++
연산자를 교체 할 수 있습니다 .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)
}
+
, -
, *
, /
, %
자 .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
는 *
문자 를 사용하지 않고 포인터 유형을 표시 할 수 없으므로 함수 의 첫 번째 인수를 사용합니다 .type[]
type* const
FWIW, AndreyT가0x55555556
제안한 트릭을 사용하기 위해 비슷한 트릭을 사용하여 곱셈 함수를 쉽게 구현할 수 있습니다 .
int mul(int const x, int const y) {
return sizeof(struct {
char const ignore[y];
}[x]);
}
++
: 왜 간단하게 사용하지 /=
않습니까?
++
는 바로 가기이기도합니다. For num = num + 1
.
+=
마침내 바로 가기입니다 num = num + 1
.
정수를 3으로 나누려면 오른쪽으로 1 자리 이동하십시오 .
그래도 그러한 플랫폼에서 적합한 C 컴파일러를 구현할 수 있는지 확실하지 않습니다. "최소 8 비트"를 "최소한 정수를 -128에서 +127까지 보유 할 수있는"것으로 해석하는 것과 같이 규칙을 약간 확장해야 할 수도 있습니다.
>>
연산자는 "2 ^ n으로 나누기"연산자입니다. 즉, 기계 표현이 아니라 산술로 지정됩니다.
내 해결책은 다음과 같습니다.
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);
}
먼저
1/3 = 1/4 + 1/16 + 1/64 + ...
이제 나머지는 간단합니다!
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 + ...
이제 우리가해야 할 일은 비트 시프트 된 값을 합산하는 것입니다! 죄송합니다! 우리는 추가 할 수 없으므로 대신 비트 연산자를 사용하여 추가 기능을 작성해야합니다! 비트 단위 연산자에 익숙하다면 내 솔루션은 상당히 단순 해 보일 것입니다 ...하지만 그렇지 않은 경우에는 예제를 살펴 보겠습니다.
주목해야 할 또 다른 사항은 먼저 30을 왼쪽으로 이동한다는 것입니다! 이것은 분수가 반올림되지 않도록하기위한 것입니다.
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!
어릴 적 배운 것만 더하면됩니다!
111
1011
+0110
-----
10001
방정식의 모든 항을 추가 할 수 없기 때문에이 구현이 실패했습니다 .
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
reslut div_by_3(a)
= x를 가정 한 다음을 가정하십시오 x <= floor(f(a, i)) < a / 3
. 때 a = 3k
, 우리는 오답을 얻는다.
n/3
은 항상보다 작습니다 n/3
. 즉 n=3k
, 결과에 대해 k-1
대신 표시됩니다 k
.
32 비트 숫자를 3으로 나누려면 숫자를 곱한 0x55555556
다음 64 비트 결과의 상위 32 비트를 취할 수 있습니다.
이제해야 할 일은 비트 연산과 시프트를 사용하여 곱셈을 구현하는 것입니다.
multiply it
. 금지 된 *
연산자를 사용하는 것을 의미하지 않습니까?
또 다른 해결책. 이것은 하드 코딩 된 예외로 처리 해야하는 int의 최소값을 제외하고 모든 음수 (음수 정수 포함)를 처리해야합니다. 이것은 기본적으로 빼기로 나누지 만 비트 연산자 (shift, xor 및 &) 만 사용합니다. 더 빠른 속도를 위해 3 *를 뺍니다 (감소 력 2). C #에서는 밀리 초당 약 444 개의 DivideBy3 호출 (1,000,000 나누기의 경우 2.2 초)을 실행하므로 끔찍하게 느리지는 않지만 단순한 x / 3만큼 빠르지는 않습니다. 이에 비해 Coodey의 훌륭한 솔루션은이 솔루션보다 약 5 배 빠릅니다.
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;
}
이것은 내가 편리했던 것이기 때문에 c #이지만 c와의 차이는 적어야합니다.
(a >= sub)
빼기로 계산 됩니까 ?
정말 쉽습니다.
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;
(물론 간결하게하기 위해 일부 프로그램을 생략했습니다.) 프로그래머가이 모든 것을 입력하는 데 지치면 프로그래머가 별도의 프로그램을 작성하여 생성 할 수 있다고 확신합니다. 나는 /
자신의 일을 엄청나게 단순화 시키는 특정 운영자를 알고 있다.
Dictionary<number, number>
반복 대신에 if
당신이 할 수 있도록 문 O(1)
시간 복잡도를!
카운터 사용은 기본 솔루션입니다.
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
}
}
모듈러스 기능을 수행하기도 쉽고, 주석을 확인하십시오.
이것은 기본 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);
}
파스칼로 프로그램을 작성하고 DIV
연산자를 사용하십시오 .
질문에 태그가 붙어 있기 때문에 씨파스칼로 함수를 작성하고 C 프로그램에서 함수를 호출 할 수 있습니다. 그렇게하는 방법은 시스템마다 다릅니다.
그러나 Free Pascal fp-compiler
패키지가 설치된 Ubuntu 시스템에서 작동하는 예제가 있습니다 . (나는 잘못 배치 된 고집에서 이것을하고 있습니다. 나는 이것이 유용하다고 주장하지 않습니다.)
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;
}
짓다:
fpc divide_by_3.pas && gcc divide_by_3.o main.c -o main
샘플 실행 :
$ ./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
있으며 INC
동일한 opcode가 없습니다.
이 답변이 이미 게시되어 있는지 확인하지 않았습니다. 프로그램을 부동 숫자로 확장해야하는 경우 숫자에 필요한 10 * 정밀도를 곱한 후 다음 코드를 다시 적용 할 수 있습니다.
#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;
}
이것은 세 개뿐만 아니라 모든 제수에게도 효과가 있습니다. 현재는 서명되지 않은 사용자에게만 해당하지만 서명 된 것으로 확장하는 것이 그렇게 어렵지 않아야합니다.
#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;
}
다음 스크립트는 연산자를 사용하지 않고 문제를 해결하는 C 프로그램을 생성합니다 * / + - %
.
#!/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));
}
''')
사용하여 해커의 기쁨 매직 번호 계산기
int divideByThree(int num)
{
return (fma(num, 1431655766, 0) >> 32);
}
여기서 fma 는 math.h
헤더에 정의 된 표준 라이브러리 함수 입니다.
-
와 *
연산자를 어떻게 사용 하지 않습니까?
정답은 다음과 같습니다.
기본 연산자를 사용하여 기본 작업을 수행하지 않는 이유는 무엇입니까?
fma () 라이브러리 함수를 사용하는 솔루션 은 모든 양수에 작동합니다.
#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의 Accelerate 프레임 워크의 일부로 포함 된 cblas를 사용하십시오 .
[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
먼저:
x/3 = (x/4) / (1-1/4)
그런 다음 x / (1-y)를 해결하는 방법을 찾으십시오.
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 인 경우 :
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)
}
비록을 사용 +
하지만 누군가가 이미 비트 단위 연산으로 add를 구현합니다.