大数四则运算

快来打我* 2022-07-17 04:17 274阅读 0赞
  1. .cpp
  2. #include"BigData.h"
  3. BigData::BigData(INT64 value)
  4. :_value(value)
  5. {
  6. INT64ToString(); //构造函数时将数字转换为字符串
  7. }
  8. BigData::BigData(const char* pData)//对大数进行处理.
  9. {
  10. //几种情况:" ","+123456","00001234","12345xyz","123456789";
  11. if (NULL == pData) //如果是空
  12. {
  13. assert(false ); //断言false,返回
  14. return;
  15. }
  16. char* pStr = (char *)pData;
  17. char cSymbol = pData [0];//第一位
  18. if ('+' == cSymbol || '-' == cSymbol)
  19. {
  20. pStr++; //后移
  21. }
  22. else if (cSymbol >= '0' && cSymbol <= '9')
  23. {
  24. cSymbol = '+'; //将符号位置为+
  25. }
  26. else
  27. return;
  28. //处理"000000000000001234" 情况
  29. while ('0' == *pStr)
  30. {
  31. pStr++;
  32. }
  33. //处理 带字母的情况
  34. _strData.resize(strlen( pData) + 1);//string中resize()函数改变本字符串的大小
  35. _strData[0] = cSymbol; //第一位存放符号位
  36. _value = 0;
  37. int icount = 1;
  38. while (*pStr >= '0' && *pStr <= '9') //字母不处理,丢弃
  39. {
  40. _value = 10 * _value + *pStr - '0';
  41. _strData[icount++] = *pStr;
  42. pStr++;
  43. }
  44. _strData.resize(icount); //将本字符串的大小调到icount
  45. if ('-' == cSymbol) //负数
  46. {
  47. _value = 0 - _value; //负值
  48. }
  49. }
  50. bool BigData ::IsINT64OverFlow()const//溢出判断
  51. {//64位中数字范围为:[-Ox8FFFFFFF FFFFFFFF,Ox7FFFFFFF FFFFFFFF]
  52. std:: string temp = "+9223372036854775807" ;
  53. if ('-' == _strData[0])
  54. {
  55. temp = "-9223372036854775808";
  56. }
  57. //1.比较该大数与边界的size。2.相等时进行字符串直接比较
  58. if (_strData.size() < temp.size() || _strData.size() == temp.size() && _strData <= temp)
  59. return true ;
  60. else
  61. return false ;
  62. }
  63. void BigData ::INT64ToString()//将value转换为字符串
  64. {//append()在字符串的末尾添加num个字符ch-----basic_string &(append(size_t num,char ch))
  65. char cSymbol = '+' ; //正号
  66. if (_value < 0)
  67. {
  68. cSymbol = '-';
  69. }
  70. //12345->"54321"
  71. INT64 temp = _value;
  72. _strData.append(1, cSymbol); //先添加符号位
  73. if (cSymbol == '-' )//负数转变成正数再模除
  74. {
  75. temp = 0 - temp;
  76. }
  77. while (temp)
  78. {
  79. _strData.append(1, temp % 10 + '0');
  80. temp /= 10;
  81. }
  82. //"54321"->"12345"
  83. char* pLeft = (char *)_strData.c_str() + 1;
  84. char* pRight = pLeft + _strData.size() - 2;//包含符号位,故减2
  85. while (pLeft < pRight) //倒序交换
  86. {
  87. char tmp = *pLeft;
  88. *pLeft = *pRight;
  89. *pRight = tmp;
  90. pLeft++;
  91. pRight--;
  92. }
  93. }
  94. //operator<<
  95. std::ostream& (operator<<(std:: ostream& _cout , const BigData& bigdata))//输出大数
  96. {//判断是否溢出,'+'不需要输出
  97. if (bigdata .IsINT64OverFlow())//没有溢出
  98. {
  99. _cout << bigdata ._value << std::endl;
  100. }
  101. else
  102. { //c_str()函数返回一个指向正规C字符串的指针, 内容与本字符串相同
  103. char* pData = (char *)bigdata._strData.c_str();
  104. if ('+' == pData[0])
  105. pData++;
  106. _cout << pData << std::endl;
  107. }
  108. return _cout ;
  109. }
  110. //operator+
  111. BigData BigData ::operator+(const BigData& bigdata )
  112. {
  113. //两个数都没溢出,结果也没溢出,直接进行相加
  114. if (IsINT64OverFlow() && bigdata .IsINT64OverFlow())
  115. {
  116. //异号
  117. if (_strData[0] != bigdata ._strData[0])
  118. {
  119. return _value + bigdata ._value;
  120. }
  121. else //同号
  122. { //两个数同号,没溢出的情况:如果边界是10,则10-3=7>=6 8,-10-(-3)=-7=<-6 -8
  123. //正数时,最大值-value>=结果,才不会溢出
  124. //负数时,最大负数-value<=结果,才不会溢出
  125. if ((_value >= 0 && (MAX_INT64 - _value >= bigdata._value)) ||
  126. (_value < 0 && (MIN_INT64 - _value <= bigdata._value)))
  127. {
  128. return _value + bigdata ._value;
  129. }
  130. else //溢出->调用溢出加法
  131. {
  132. return BigData (Add(_strData, bigdata._strData).c_str());
  133. }
  134. }
  135. }
  136. //两个数至少一个溢出,结果溢出
  137. if (_strData[0] == bigdata ._strData[0]) //同号
  138. {
  139. return BigData (Add(_strData, bigdata._strData).c_str());
  140. }
  141. //异号
  142. else
  143. { //两个数异号a,b;b为正数需要换负号,b为负数需要换正号
  144. //将b的符号进行转换,在调用大数减法
  145. string _StrData = bigdata ._strData;//注意定义字符串
  146. if (_StrData[0] == '+' )
  147. {
  148. _StrData[0] = '-';
  149. }
  150. else
  151. {
  152. _StrData[0] = '+';
  153. }
  154. return BigData (Sub(_strData, _StrData).c_str());
  155. }
  156. }
  157. //溢出加法
  158. std::string BigData::Add(std::string left, std:: string right )
  159. {
  160. int iLsize = left .size(); //size
  161. int iRsize = right .size();
  162. if (iLsize < iRsize)//选出大的长度给iLsize
  163. {
  164. std::swap( left, right );
  165. std::swap(iLsize, iRsize);
  166. }
  167. std:: string sRet;
  168. sRet.resize(iLsize + 1); //相加不会超过较大数的size+1
  169. sRet[0] = left[0];
  170. char Step = 0;//进位标识符
  171. //
  172. //模除得到每位的数字及进位Step
  173. for (int iIdx = 1; iIdx < iLsize; iIdx++)
  174. {
  175. int cRet = left [iLsize - iIdx] + Step - '0';
  176. if (iIdx < iRsize)
  177. {
  178. cRet += right[iRsize - iIdx] - '0' ;//cRet转为数字:-‘0’
  179. }
  180. sRet[iLsize - iIdx + 1] = cRet % 10 + '0';//sRet比iLsize多一位,存放字符,故+‘0’
  181. Step = cRet / 10;
  182. }
  183. sRet[1] = Step + '0'; //???
  184. return sRet;
  185. }
  186. BigData BigData ::operator-(const BigData& bigdata )
  187. {
  188. //两个数都没溢出,结果也没溢出,相减
  189. if (IsINT64OverFlow() && bigdata .IsINT64OverFlow())
  190. {
  191. if (_strData[0] == bigdata ._strData[0])
  192. {
  193. return _value - bigdata ._value; //
  194. }
  195. else
  196. {
  197. //两个数异号,相减没溢出
  198. //-10 + 3 = -7 <= -6(减式:3-(-6));10+(-3)= 7 >= 6(减式:-3-(6))
  199. if (_value >= 0 && (MIN_INT64 + _value <= bigdata._value) ||
  200. _value < 0 && (MAX_INT64 + _value >= bigdata._value))
  201. {
  202. return _value + bigdata ._value;
  203. }
  204. else
  205. { //调用溢出加法
  206. BigData(Add(_strData, bigdata._strData).c_str());
  207. }
  208. }
  209. }
  210. //两个数至少一个溢出,
  211. //同号调用减法
  212. if (_strData[0] == bigdata ._strData[0])
  213. {
  214. return BigData (Sub(_strData, bigdata._strData).c_str());
  215. }
  216. else //异号调用加法
  217. {
  218. return BigData (Add(_strData, bigdata._strData).c_str());
  219. }
  220. }
  221. std::string BigData::Sub(std::string left, std:: string right )
  222. {
  223. int iLsize = left .size();
  224. int iRsize = right .size();
  225. char cSymbol = left [0];//符号位
  226. if (iLsize < iRsize || (iLsize == iRsize && left < right))//左边小于右边都进行交换
  227. { //-12-(-21)=9,21-34=-13发现两数的差与减数的相反
  228. std::swap( left, right );
  229. std::swap(iLsize, iRsize);
  230. if (cSymbol == '-' )
  231. {
  232. cSymbol = '+';
  233. }
  234. else
  235. {
  236. cSymbol = '-';
  237. }
  238. }
  239. std:: string sRet;
  240. sRet.resize(iLsize); //用大的长度进行开辟空间
  241. sRet[0] = cSymbol; //保存符号位
  242. for (int iIdx = 1; iIdx < iLsize; iIdx++)//结束标志为iLsize-1,不是iLsize
  243. {
  244. //从低到高,取left每一位;
  245. char cRet = left [iLsize - iIdx] - '0';
  246. //在right范围内从低到高,取right每一位,然后相减;
  247. if (iIdx < iRsize)
  248. {
  249. cRet -= right[iRsize - iIdx] - '0' ;
  250. }
  251. //判断是否借位
  252. if (cRet < 0)
  253. {
  254. left[iLsize - iIdx - 1] -= 1; //上一位减一
  255. cRet += 10; //
  256. }
  257. sRet[iLsize - iIdx] = cRet + '0';
  258. }
  259. return sRet;
  260. }
  261. BigData BigData ::operator*(const BigData& bigdata )
  262. {//无溢出
  263. if (IsINT64OverFlow() && bigdata .IsINT64OverFlow())
  264. {
  265. if (_strData[0] == bigdata ._strData[0])//同号
  266. {
  267. //例如:边界是10,10 / 2 = 5 > 4; 10 / -2 = -5 < -4;
  268. //结果不会溢出
  269. if (_value > 0 && MAX_INT64 / _value >= bigdata._value ||
  270. _value < 0 && MAX_INT64 / _value <= bigdata._value)
  271. {
  272. return _value*bigdata ._value;
  273. }
  274. }
  275. else //异号
  276. {
  277. //例如:边界是-10,-10 / 2 = -5 < -4; -10 / -2 = 5 > 4;
  278. //不会溢出
  279. if (_value>0 && MIN_INT64 / _value <= bigdata._value ||
  280. _value < 0 && MIN_INT64 / _value >= bigdata._value)
  281. {
  282. return _value*bigdata ._value;
  283. }
  284. }
  285. }
  286. //两数至少有一个溢出
  287. if (_value != 0 && bigdata ._value != 0)
  288. {
  289. return BigData (Mul(_strData, bigdata._strData).c_str());
  290. }
  291. }
  292. //溢出乘法
  293. std::string BigData::Mul(std::string left, std:: string right )
  294. {
  295. int iLsize = left .size();
  296. int iRsize = right .size();
  297. char cSymbol = '+' ;//确认符号位
  298. if (left [0] != right[0])
  299. {
  300. cSymbol = '-';
  301. }
  302. if (iLsize > iRsize)//使较小的数为left,提高效率。eg:99*12345678
  303. {
  304. swap( left, right );
  305. swap(iLsize, iRsize);
  306. }
  307. std:: string sRet;
  308. //两个数相乘最大位数为两个数位数的和,left和right中有符号位故减1
  309. sRet.assign(iLsize + iRsize - 1, '0');//assign()为字符串赋新值'0'
  310. sRet[0] = cSymbol;
  311. int iDataLen = iLsize + iRsize - 1;
  312. int ioffset = 0;//pian移位
  313. //先取左边一位和右边相乘;再考虑移位可得到左边每位与右边相乘的结果
  314. for (int iLdx = 1; iLdx < iLsize; iLdx++)
  315. {
  316. char cLeft = left [iLsize - iLdx] - '0';
  317. if (cLeft == 0)//如果left中含有0,偏移量加1
  318. {
  319. ioffset++;
  320. continue;
  321. }
  322. char Step = 0;
  323. //99*999=89910+8991;
  324. for (int iRdx = 1; iRdx < iRsize; iRdx++)
  325. {
  326. char cRet = cLeft * (right [iRsize - iRdx] - '0') + Step;
  327. cRet += sRet[iDataLen - iRdx - ioffset] - '0';//cRet存放当前最终乘加的结果
  328. sRet[iDataLen - iRdx - ioffset] = cRet % 10 + '0';//存放字符+'0'
  329. Step = cRet / 10;
  330. }
  331. sRet[iDataLen - iRsize - ioffset] += Step;
  332. ioffset++;
  333. }
  334. return sRet;
  335. }
  336. BigData BigData ::operator/(const BigData& bigdata )
  337. {
  338. //1、除数为0
  339. if (bigdata ._strData[1] == '0')
  340. {
  341. assert(false );
  342. }
  343. //2、两个数没溢出
  344. if (IsINT64OverFlow() && bigdata .IsINT64OverFlow())
  345. {
  346. return _value / bigdata ._value;
  347. }
  348. //3、除数为1或-1
  349. if (bigdata ._value == 1 || bigdata._value == -1)
  350. {
  351. return _value;
  352. }
  353. //4、除数和被除数相等
  354. //data()返回内容的字符数组形式
  355. if (strcmp(_strData.c_str() + 1, bigdata ._strData.c_str() + 1) == 0)
  356. {
  357. if (_strData[0] != bigdata ._strData[0])
  358. {
  359. return BigData (INT64(-1));
  360. }
  361. return BigData (INT64(1));
  362. }
  363. //除数大于被除数,返回0
  364. if (_strData.size() < bigdata ._strData.size() ||
  365. _strData.size() == bigdata._strData.size() &&
  366. strcmp(_strData.c_str() + 1, bigdata._strData.c_str() + 1) < 0)
  367. {
  368. return BigData (INT64(0));
  369. }
  370. //调用溢出除法
  371. return BigData (Div(_strData, bigdata._strData).c_str());
  372. }
  373. std::string BigData::Div(std::string left, std:: string right )
  374. {//此处用append()对字符串依次赋值
  375. std:: string sRet;
  376. sRet.append(1, '+');
  377. if (left [0] != right[0])
  378. {
  379. sRet[0] = '-';
  380. }
  381. char* pLeft = (char *)left.c_str() + 1;
  382. char* pRight = (char *)right.c_str() + 1;
  383. int DataLen = right .size() - 1;//标记相除的除数位数
  384. int Lsize = left .size() - 1;
  385. int Rsize = right .size() - 1;
  386. //eg:222222/33首先取到22和33比较大小,如果大就直接相除,否则DataLen++;
  387. for (int iIdx = 0; iIdx < Lsize;)
  388. {
  389. if (!(IsLeftstrBig(pLeft, DataLen, pRight, Rsize)))//如果取到的数小于除数时,结果商0,向后再取一位
  390. {
  391. sRet.append(1, '0');
  392. DataLen++;
  393. }
  394. else
  395. {
  396. sRet.append(1, SubLoop(pLeft, DataLen, pRight, Rsize));//循环相减得到该位的商
  397. //判断pLeft中进行循环相减后依次去掉0,
  398. while (*pLeft == '0' && DataLen > 0)
  399. {
  400. pLeft++;
  401. DataLen--;
  402. iIdx++;
  403. }
  404. DataLen++;
  405. }
  406. if (DataLen > Rsize + 1)//pLeft比pRight大一位结果为0,则pLeft中含有0
  407. {
  408. pLeft++;
  409. DataLen--;
  410. iIdx++;
  411. }
  412. if (DataLen + iIdx > Lsize)//判断是否除法结束
  413. break;
  414. }
  415. return sRet;
  416. }
  417. //循环相减
  418. char BigData ::SubLoop(char* pLeft, int Lsize, const char * pRight, int Rsize)
  419. {
  420. assert(pLeft && pRight);
  421. char cRet = 0;
  422. while (IsLeftstrBig(pLeft , Lsize, pRight, Rsize ))//直到被减数小于减数停止运算
  423. {
  424. for (int iIdx = 0; iIdx < Rsize; iIdx++) //进行减运算
  425. {
  426. char ret = pLeft [Lsize - iIdx - 1] - '0';
  427. ret -= pRight[Rsize - iIdx - 1] - '0';
  428. if (ret < 0)
  429. {
  430. pLeft[Lsize - iIdx - 2] -= 1;
  431. ret += 10;
  432. }
  433. pLeft[Lsize - iIdx - 1] = ret + '0';
  434. }
  435. while (*pLeft == '0'&& Lsize>0)
  436. {
  437. pLeft++;
  438. Lsize--;
  439. }
  440. cRet++;
  441. }
  442. return cRet + '0' ;
  443. }
  444. //判断是否left大于right
  445. bool BigData ::IsLeftstrBig(const char* pLeft , int Lsize, const char * pRight, int Rsize)
  446. {
  447. assert(pLeft && pRight);
  448. char* pleft = (char *)pLeft;
  449. char* pright = (char *)pRight;
  450. if (Lsize > Rsize && *pleft > '0')//eg:112和33
  451. {
  452. return true ;
  453. }
  454. else if (Lsize == Rsize)//eg:57和33
  455. {
  456. while (pright)
  457. {
  458. if (*pleft > *pright)
  459. {
  460. return true ;
  461. }
  462. else if (*pleft == *pright)
  463. {
  464. pleft++;
  465. pright++;
  466. }
  467. else
  468. return false ;
  469. }
  470. }
  471. return false ;
  472. }
  473. .h
  474. #ifndef BIG_DATA_H
  475. #define BIG_DATA_H
  476. #include<iostream>
  477. using namespace std;
  478. #include<assert.h>
  479. #include<string>
  480. #define UN_INTT 0xCCCCCCCCCCCCCCCC
  481. #define MAX_INT64 0x7FFFFFFFFFFFFFFF
  482. #define MIN_INT64 0x8000000000000000
  483. typedef long long INT64;
  484. //内置类型
  485. class BigData
  486. {
  487. public:
  488. BigData( INT64 value);
  489. BigData( const char * pData);//对大数进行处理,优化
  490. friend std::ostream & (operator<<(std::ostream& _cout, const BigData& bigdata));//输出大数
  491. public:
  492. //大数的四则运算
  493. BigData operator+(const BigData& bigdata); //返回值不能传引用
  494. BigData operator-(const BigData& bigdata);
  495. BigData operator*(const BigData& bigdata);
  496. BigData operator/(const BigData& bigdata);
  497. std:: string Add(std::string left, std::string right);
  498. std:: string Sub(std::string left, std::string right);
  499. std:: string Mul(std::string left, std::string right);
  500. std:: string Div(std::string left, std::string right);
  501. private:
  502. bool IsINT64OverFlow()const ;//判断大数是否溢出
  503. void INT64ToString();//由于值在_value中,需将_value转化成string类型
  504. char SubLoop(char * pLeft, int Lsize, const char * pRight, int Rsize);//循环相减
  505. bool IsLeftstrBig(const char* pLeft, int Lsize, const char* pRight, int Rsize);//判断是否left大于right
  506. private:
  507. std:: string _strData;
  508. INT64 _value;
  509. };
  510. #endif
  511. test.cpp
  512. #define _CRT_SECURE_NO_WARNINGS 1
  513. #include<iostream>
  514. using namespace std;
  515. #include"BigData.h"
  516. void Test1()
  517. {
  518. //BigData b1(1234);
  519. //BigData b2("123456");
  520. //BigData b3("+1234567");
  521. //BigData b4("+1234567aaaa");
  522. //BigData b5("+");
  523. //BigData b6(" ");
  524. //BigData b7("-12345678");
  525. //BigData b8("-0000000012345aaa");
  526. //cout << b1 << endl;
  527. //cout << b2 << endl;
  528. //cout << b3 << endl;
  529. //cout << b4 << endl;
  530. //cout << b5 << endl;
  531. //cout << b6 << endl;
  532. //cout << b7 << endl;
  533. //cout << b8 << endl;
  534. //b3 = b2 + b1;
  535. }
  536. //test Add
  537. void Test2()
  538. {
  539. /*BigData left1(1234);
  540. BigData right1(4321);
  541. BigData ret = (left1 + right1);
  542. cout << ret << endl;*/
  543. /*BigData left2(9223372036854775807);
  544. BigData right2(2);
  545. BigData ret = (left2 + right2);
  546. cout << ret << endl;*/
  547. /*BigData left3(-9223372036854775807);
  548. cout << left3 << endl;
  549. BigData right3(-6);
  550. cout << right3 << endl;
  551. BigData ret = (left3 + right3);
  552. cout << ret << endl;*/
  553. /*BigData left2("999999999999999999999999999999");
  554. cout << left2 << endl;
  555. BigData right2("111111111111111111111111111111");
  556. cout << right2 << endl;
  557. BigData ret = (left2 + right2);
  558. cout << ret << endl;*/
  559. }
  560. void Test3()
  561. {
  562. /* BigData left2(1234);
  563. cout << left2 << endl;
  564. BigData right2(34);
  565. cout << right2 << endl;
  566. BigData ret = (left2 - right2);
  567. cout << ret << endl;*/
  568. /*BigData left2(9223372036854775807);
  569. cout << left2 << endl;
  570. BigData right2(-999);
  571. cout << right2 << endl;
  572. BigData ret = (left2 - right2);
  573. cout << ret << endl;*/
  574. /*BigData left2(9223372036854775807);
  575. cout << left2 << endl;
  576. BigData right2(999);
  577. cout << right2 << endl;
  578. BigData ret = (left2 - right2);
  579. cout << ret << endl;*/
  580. /*BigData left2(-9223372036854775807);
  581. cout << left2 << endl;
  582. BigData right2(-999);
  583. cout << right2 << endl;
  584. BigData ret = (left2 - right2);
  585. cout << ret << endl;*/
  586. BigData left2("1111111111111111111111111111111111111" );
  587. cout << left2 << endl;
  588. BigData right2("99" );
  589. cout << right2 << endl;
  590. BigData ret = (left2 - right2);
  591. cout << ret << endl;
  592. BigData left3(9223372036854775807);
  593. cout << left3 << endl;
  594. BigData right3("-999" );
  595. cout << right3 << endl;
  596. BigData ret3 = (left3 - right3);
  597. cout << ret3 << endl;
  598. }
  599. //test mul
  600. void Test4()
  601. {
  602. /*BigData left2("999");
  603. cout << left2 << endl;
  604. BigData right2("9999999999999999999999999999999999999999");
  605. cout << right2 << endl;
  606. BigData ret = (left2 * right2);
  607. cout << ret << endl;
  608. */
  609. /*BigData left2("-999");
  610. cout << left2 << endl;
  611. BigData right2("99999999999999");
  612. cout << right2 << endl;
  613. BigData ret = (left2 * right2);
  614. cout << ret << endl;*/
  615. }
  616. //Div
  617. void Test5()
  618. {
  619. /*BigData left1(1234);
  620. BigData right1(4321);
  621. BigData ret = (left1 / right1);
  622. cout << ret << endl;*/
  623. /*BigData left1(123456789);
  624. BigData right1(4321);
  625. BigData ret = (left1 / right1);
  626. cout << ret << endl;*/
  627. BigData left2("999999999999999999999999999999" );
  628. //cout << left2 << endl;
  629. BigData right2("111111111111111111111111111111" );
  630. //cout << right2 << endl;
  631. BigData ret = (left2 / right2);
  632. cout << ret << endl;
  633. }
  634. int main()
  635. {
  636. //Test1();
  637. //Test2();
  638. //Test3();
  639. //Test4();
  640. Test5();
  641. system( "pause");
  642. return 0;
  643. }

发表评论

表情:
评论列表 (有 0 条评论,274人围观)

还没有评论,来说两句吧...

相关阅读

    相关 有理数四则运算

    本题要求编写程序,计算 2 个有理数的和、差、积、商。 输入格式: 输入在一行中按照 a1/b1 a2/b2 的格式给出两个分数形式的有理数,其中分子和分母全是整型范围