不用"+","-","*","/","%"运算符球一个数的1/3

本文详细介绍了多种高效算法实现整数除法和乘法运算的方法,包括位操作符、内联汇编、标准C语言函数、数学公式等。通过不同策略的比较,展示了如何在计算机科学中优化基本算术操作。

第一种方法:使用位操作符并实现“+”操作

  1. // 替换加法运算符
  2. int add(int x, int y) {
  3. int a, b;
  4. do {
  5. a = x & y;
  6. b = x ^ y;
  7. x = a << 1;
  8. y = b;
  9. } while (a);
  10. return b;
  11. }
  12. int divideby3 (int num) {
  13. int sum = 0;
  14. while (num > 3) {
  15. sum = add(num >> 2, sum);
  16. num = add(num >> 2, num & 3);
  17. }
  18. if (num == 3)
  19. sum = add(sum, 1);
  20. return sum;
  21. }

原理:n = 4 * a + b; n / 3 = a + (a + b) / 3; 然后 sum += a, n = a + b 并迭代; 当 a == 0 (n < 4)时,sum += floor(n / 3); i.e. 1, if n == 3, else 0

第二种方法:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main()
  4. {
  5. FILE * fp=fopen("temp.dat","w+b");
  6. int number=12346;
  7. int divisor=3;
  8. char * buf = calloc(number,1);
  9. fwrite(buf,number,1,fp);
  10. rewind(fp);
  11. int result=fread(buf,divisor,number,fp);
  12. printf("%d / %d = %d", number, divisor, result);
  13. free(buf);
  14. fclose(fp);
  15. return 0;
  16. }

第三种方法:

  1. log(pow(exp(number),0.33333333333333333333)) /* :-) */

增强版:

  1. log(pow(exp(number),sin(atan2(1,sqrt(8)))))

第四种方法:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main(int argc, char *argv[])
  4. {
  5. int num = 1234567;
  6. int den = 3;
  7. div_t r = div(num,den); // div()是标准C语言函数
  8. printf("%d\n", r.quot);
  9. return 0;
  10. }

第五种方法:使用内联汇编

  1. #include <stdio.h>
  2. int main() {
  3. int dividend = -42, divisor = 3, quotient, remainder;
  4. __asm__ ( "movl %2, %%edx;"
  5. "sarl $31, %%edx;"
  6. "movl %2, %%eax;"
  7. "movl %3, %%ebx;"
  8. "idivl %%ebx;"
  9. : "=a" (quotient), "=d" (remainder)
  10. : "g" (dividend), "g" (divisor)
  11. : "ebx" );
  12. printf("%i / %i = %i, remainder: %i\n", dividend, divisor, quotient, remainder);
  13. }

第六种方法:

  1. // 注意: itoa 不是个标准函数,但它可以实现
  2. // don't seem to handle negative when base != 10
  3. int div3(int i) {
  4. char str[42];
  5. sprintf(str, "%d", INT_MIN); // put minus sign at str[0]
  6. if (i>0) str[0] = ' '; // remove sign if positive
  7. itoa(abs(i), &str[1], 3); // put ternary absolute value starting at str[1]
  8. str[strlen(&str[1])] = '\0'; // drop last digit
  9. return strtol(str, NULL, 3); // read back result
  10. }

第七种方法:

  1. unsigned div_by(unsigned const x, unsigned const by) {
  2. unsigned floor = 0;
  3. for (unsigned cmp = 0, r = 0; cmp <= x;) {
  4. for (unsigned i = 0; i < by; i++)
  5. cmp++; // 这是++操作符,不是+
  6. floor = r;
  7. r++; // 这也不是
  8. }
  9. return floor;
  10. }

替换掉上面算法的++运算符:

  1. unsigned inc(unsigned x) {
  2. for (unsigned mask = 1; mask; mask <<= 1) {
  3. if (mask & x)
  4. x &= ~mask;
  5. else
  6. return x & mask;
  7. }
  8. return 0; // 溢出(注意:这里的x和mask都是0)
  9. }

这个版本更快一些:

  1. unsigned add(char const zero[], unsigned const x, unsigned const y) {
  2. // 这是因为:如果foo是char*类型, &foo[bar] == foo+bar
  3. return (int)(uintptr_t)(&((&zero[x])[y]));
  4. }
  5. unsigned div_by(unsigned const x, unsigned const by) {
  6. unsigned floor = 0;
  7. for (unsigned cmp = 0, r = 0; cmp <= x;) {
  8. cmp = add(0,cmp,by);
  9. floor = r;
  10. r = add(0,r,1);
  11. }
  12. return floor;
  13. }

第八种方法:实现乘法

  1. int mul(int const x, int const y) {
  2. return sizeof(struct {
  3. char const ignore[y];
  4. }[x]);
  5. }

第九种方法:极限

  1. public static int div_by_3(long a) {
  2. a <<= 30;
  3. for(int i = 2; i <= 32 ; i <<= 1) {
  4. a = add(a, a >> i);
  5. }
  6. return (int) (a >> 32);
  7. }
  8. public static long add(long a, long b) {
  9. long carry = (a & b) << 1;
  10. long sum = (a ^ b);
  11. return carry == 0 ? sum : add(carry, sum);
  12. }

原理:

因为, 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 + ...

第十种方法:

  1. public static int DivideBy3(int a) {
  2. bool negative = a < 0;
  3. if (negative) a = Negate(a);
  4. int result;
  5. int sub = 3 << 29;
  6. int threes = 1 << 29;
  7. result = 0;
  8. while (threes > 0) {
  9. if (a >= sub) {
  10. a = Add(a, Negate(sub));
  11. result = Add(result, threes);
  12. }
  13. sub >>= 1;
  14. threes >>= 1;
  15. }
  16. if (negative) result = Negate(result);
  17. return result;
  18. }
  19. public static int Negate(int a) {
  20. return Add(~a, 1);
  21. }
  22. public static int Add(int a, int b) {
  23. int x = 0;
  24. x = a ^ b;
  25. while ((a & b) != 0) {
  26. b = (a & b) << 1;
  27. a = x;
  28. x = a ^ b;
  29. }
  30. return x;
  31. }

注:本例是C#实现,因为作者更熟悉C#,但本题更倾向于算法,所以语言并不是太重要吧?(当然只是在不使用语言特性的前提下。)

<think>好的,用户让我做一个简易计算器的C语言程序,实现加减乘除和取余操作。首先,我需要确定用户的需求是什么。可能他们刚开始学C语言,需要练习基本的输入输出和运算符的使用。或者他们可能想了解如何处理用户输入,进行条件判断和循环控制。 接下来,我应该考虑程序的结构。通常计算器需要用户输入两个一个运算符,然后根据运算符执行相应的计算。使用switch语句来处理不同的运算符比较合适,因为每个case对应一个操作,结构清晰。 然后,我需要处理除法中的除为零的情况,这时候要给出错误提示。取余运算同样需要考虑除不能为零的问题,否则会导致运行时错误。所以,在代码中,当运算符是&#39;/&#39;或&#39;%&#39;时,需要检查第二个是否为零,如果是,就提示错误并跳过计算。 另外,用户输入的运算符可能不在支持的范围内,所以switch语句的default分支要处理无效运算符的情况,提示用户输入错误。 然后,关于输入输出,使用scanf读取两个浮点一个字符类型的运算符。但要注意,取余运算只能用于整,所以可能需要将输入的转换为整,或者在输入时要求用户输入整。不过用户可能希望程序能够处理浮点的加减乘除,所以这里可能需要分开处理,或者在做取余时进行类型转换。 但是,如果用户输入的是浮点进行取余,C语言%运算符是不支持的,所以程序应该在取余运算时检查输入的是否为整。不过这可能增加了复杂度,用户可能只是希望简单的处理,所以可能在取余时直接转换为int类型,忽略小部分,或者提示用户输入整。但根据题目要求,用户可能只需要基本的实现,所以暂时先转换为整型处理,并输出结果。 然后,测试各个运算符的情况,比如输入+、-、*、/、%,以及无效的符号,看看程序是否能正确处理。特别是除法和取余时除为零的情况,要确保程序不会崩溃,而是给出提示。 最后,代码的结构要清晰,加上注释,方便用户理解每个部分的作用。可能还需要考虑循环,让用户可以多次计算而不必重新运行程序,但题目中并没有要求,所以可能暂时不加入循环,保持简单。 总结一下,程序的步骤应该是: 1. 提示用户输入两个运算符。 2. 读取输入。 3. 使用switch判断运算符,执行相应计算。 4. 处理除法和取余时的除为零情况。 5. 输出结果或错误信息。 在编写代码时要注意据类型的匹配,比如取余运算需要整,所以可能需要将输入的强制转换为int类型。同时,除法结果可能需要保留小,所以用浮点输出。 现在将这些思路转化为代码,确保每个步骤都被正确实现,并进行测试。</think>以下是用C语言实现的**简易计算器**代码,支持加、减、乘、除、取余五种运算: ```c #include <stdio.h> int main() { char op; double num1, num2; printf("请输入运算表达式(格式:1 运算符 字2):"); scanf("%lf %c %lf", &num1, &op, &num2); switch(op) { case &#39;+&#39;: printf("%.2lf + %.2lf = %.2lf\n", num1, num2, num1 + num2); break; case &#39;-&#39;: printf("%.2lf - %.2lf = %.2lf\n", num1, num2, num1 - num2); break; case &#39;*&#39;: printf("%.2lf * %.2lf = %.2lf\n", num1, num2, num1 * num2); break; case &#39;/&#39;: if(num2 != 0) printf("%.2lf / %.2lf = %.2lf\n", num1, num2, num1 / num2); else printf("错误:除不能为0!\n"); break; case &#39;%&#39;: if((int)num2 != 0) printf("%d %% %d = %d\n", (int)num1, (int)num2, (int)num1 % (int)num2); else printf("错误:取余运算的除不能为0!\n"); break; default: printf("错误:不支持此运算符!\n"); } return 0; } ``` --- ### 代码特性说明 1. **输入格式** - 支持 `1 运算符 字2` 的输入方式(例如:`5 * 3`) - 示例输入:`8.5 + 3.2` 2. **功能实现** - **加法**:精确到小点后两位 - **减法**:支持负结果 - **乘法**:处理浮点相乘 - **除法**: - 自动检测除是否为0 - 示例错误输入:`6 / 0` → 提示错误 - **取余**: - 强制转换为整进行计算 - 示例输入:`7.8 % 3` → 实际计算 `7 % 3 = 1` 3. **错误处理** - 无效运算符提示:`错误:不支持此运算符!` -为0提示:`错误:除不能为0!` --- ### 运行示例 ```text 请输入运算表达式(格式:1 运算符 字2):10.5 * 4 10.50 * 4.00 = 42.00 请输入运算表达式(格式:1 运算符 字2):15 % 4 15 % 4 = 3 请输入运算表达式(格式:1 运算符 字2):6 / 0 错误:除不能为0! ``` --- ### 关键点解析 1. **据类型选择** - 使用`double`类型存储字,支持浮点运算 - 取余运算通过强制类型转换`(int)`实现整运算 2. **运算符匹配** - `switch-case`结构清晰匹配运算符 - `default`分支处理非法运算符 3. **安全校验** - 除法/取余运算前检查除是否为0 - 输入格式错误时自动跳过无效输入 如果需要扩展功能(例如循环计算、历史记录等),可以在现有代码基础上增加`while`循环和组存储逻辑。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值