PDA

View Full Version : Có ai biết làm thế nào để thực hiện các phép toán cơ bản trên các số cực lớn không



Pateheo
13-04-2005, 17:31
Mình vừa được cho đề tài làm về +-*/ các số có số chữ số khoảng 256 dến lớn đến mức có thể (số thực). Không biết phải làm sao, mong các bạn chỉ giùm về nguồn tài liẹu và cách thức.

songok
15-04-2005, 18:21
Theo tui nghi minh cung co the ap dung cong so thuc so lon giong nhu cong so nguyen lon, nghia la dung mang de chua. Mang cua chung ta se chua ca phan nguyen lan phan thuc, khi + - * / cung ap dung cac quy luat cua cac phep toan tren, ( cac tren phan thuc lan lan phan nguyen)

netwalker
15-04-2005, 21:50
mình có viết 1 chương trính như vậy dùng để tính 1000!
ý tưởng là thao tác trên file
và đã làm được

Pateheo
16-04-2005, 07:22
Mình chỉ sợ vói các số lớn, đống thời là các biếu thức cực kì dài, với nhiều biểu thức thì thao tác trên file sẽ làm chậm đáng kể thuật toán. Nếu bạn rành về thao tác file thì xin chỉ dùm mình cách thao tác một file ảnh bitmap trắng đen có kích thước cực lớn mà không thể nào lưu nguyên ảnh đó vào một mảng được.

Kijuto Riddle
16-04-2005, 09:05
Kijuto đã làm một bài tập lớn về C ở trường Đại học về vấn đề này. Đề bài là viết một chương trình để thực hiện các phép toán trên các số nguyên có độ dài 1000 chữ số, nhưng đó chỉ là điều kiện, nếu bạn chỉ cần làm được với các số có độ lớn gấp 3 lần đơn vị số nguyên lớn nhất hệ thống máy tính của bạn, thì về nguyên lý là có thể thực hiện được số dài vô hạn.
Vì bài tập lớn của ngôn ngữ C nên viết một kiểu dữ liệu rất lộn xộn, nếu bạn muốn, tôi sẽ gửi source cho bạn. Nhưng nhắc trước là chương trình được viết = C (không phải C++) nên rất khó đọc, lại phải viết cho trình biên dịch C 16bit, nên cũng hơi bị củ chuối. Nhưng có thể bạn sẽ nắm được ý tưởng.
Cứ dự định là có thời gian rảnh thì viết lại cho C++, nhưng thấy nó chẳng có tác dụng gì nhiều lắm, chẳng ai thèm dùng, chỉ để nghiên cứu thôi.
Một khi đã có các phép tính trên số nguyên, thì việc sử lý với số thực không có khó khăn gì. Kijuto cũng đã viết một kiểu đơn vị Fixed (số thực chấm tĩnh) từ các phép tính số nguyên cho J2ME = Java. (Chú thích: môi trường di động hiện nay hầu hết là không hỗ trợ kiểu số thực). Nếu bạn muốn Kijuto sẽ gửi source này cho, cái này viết = Java nên cũng dễ coi hơn cái trên.

Chú thích thêm, yêu cầu của bài tập lớn là làm bằng mảng ký tự, nhưng Kijuto thấy cách đó quá là dở (tốc độ quá chậm, bộ nhớ quá lãng phí) nên mới quyết định tiếp cận bằng mảng long, không bỏ phí dù chỉ là một bit. :)

htbn_hoang
16-04-2005, 09:22
Chào,
giả sử chúng ta cần lưu trữ một mảng 1000 số, mỗi số 4byte, vậy chúng ta cần 4000 byte. Con số đó có nhiều không? Chỉ là 4KB! Nếu bạn làm bằng Borland C thì có vấn đề thật nhưng với các trình biên dịch khác chạy trên nền Windows thì không có gì phải lo, bạn có thể cấp phát nhiều hơn rất nhiều.
Việc tính toán với số cực lớn thì phải dùng mảng, còn những số không thể chứa trong mảng được (cỡ 1tỷ chữ số chảng hạn) thì mới nên dùng tập tin.
Bạn có thể lưu trữ trên mảng như sau
[0] : số chữ số
[1] : bit dấu
[...] còn lại là các chữ số
Nếu cảm thấy như thế quá lảng phí, bạn có thể lưu 4 chữ số tại 1 ô [..] (0000-9999) hoặc có thể nhiều hơn nếu muốn.
Tuy nhiên, việc thao tác với mảng không hay vì chúng không cho phép mở rộng một cách nhanh chóng. Tui sẽ làm bằng danh sách liên kết hai chiều, vì các phép toán nhân có thể làm số phình to rất nhanh.
struct node
{
int value;
node* prev;
node* next;
}

các node chỉ cần lưu giá trị, node đầu tiên lưu luôn dấu

struct list
{
node* pHead;
node* pTail;
}

thực hiện phép toán + hai số nguyên dương
p1 = list1.pTail;
p2 = list2.pTail;
s=0;//biến nhớ

while (p1!=NULL & p2 !=NULL)
{
//tạo ra node mới, thêm vào danh sách
p3 = new node;
AddNode(list3,p3);

if (p1==NULL)
{
p3->value = p2->value + s;
p2 = p2 ->prev;
}
else if (p2==NULL)
{
p3->value = p1->value + s;
p1 = p1->prev;
}
else
{
p3->value = p1->value + p2->value + s;
p2 = p2->prev;
p1 = p1->prev;
}
if (p1->value>MAX)
{
p1->value -=MAX;
s = 1;
}
else
s=0;

}

if (s=1)
{
//tao node moi
p3 = new node;
AddNode(list3,p3);
p3->value=1;
}

phép cộng hai số nguyên trái dấu coi như phép trừ.
Phép trừ, nếu số lớn trừ số nhỏ thì trừ từ phải qua (trừ ngược). nếu số nhỏ trừ số lớn thì lấy số lớn trừ số nhỏ, sau đó đổi dấu.
Phép nhân là cộng liên tiếp.
Phép chia lấy phần nguyên (lấy luôn cả phần thập phân rất khó) là trừ liên tiếp
Các bạn tự cài đặt vậy nhé

Kijuto Riddle
16-04-2005, 10:08
to htbn_hoang:
performent quá chậm, sử dụng double-linker-list cho phép toán cộng trừ(!!!) ác mộng!


Phép nhân là cộng liên tiếp.
Phép chia lấy phần nguyên (lấy luôn cả phần thập phân rất khó) là trừ liên tiếp

tốc độ quá dở.
Rất tiếc, phương pháp của bạn chỉ là phương pháp, chỉ ở mức chạy được (hy vọng thế)
thực hiện một phép tính nhân hai số 100 chữ số coi như mất gần nửa ngày mới song.
Tin tôi đi, bạn chưa thử phải không? Hãy gõ ý tưởng của bạn vào máy, biên dịch, chạy thử rồi hẵng đưa ra kết luận nha.

htbn_hoang
16-04-2005, 21:34
Bạn à, tôi đã làm bài này bằng Borland C/C++ 3.1 và chạy rất tốt. Tôi đã kiểm thử với vài chục chữ số và chương trình chỉ chạy trong tích tắc. Đúng là làm việc với danh sách liên kết thì khá mạo hiểm nhưng nếu làm được sẽ hay hơn. So sánh một chút nhé:
Dùng mảng 1 chiều, nếu cộng hai số còn dư phần "nhớ" thì sao? Có phải bạn phải dịch chuyển cả mảng để có một chỗ trống để thêm phần "nhớ" vào không?
Dùng danh sách liên kết, bạn tự do thêm mà không cần dịch chuyển.
Tôi đề nghị cách khác, chúng ta sẽ lưu ngược số và dùng mảng, chúng ta sẽ thêm vào cuối mảng, như thế tốt hơn.
Tuy nhiên, đối với các bài toán yêu cầu bộ nhớ cao như thế này, việc sử dụng tối ưu bộ nhớ được yêu cầu rất cao. Và một khía cạnh nữa, nếu dùng Borland C/C++ 3.1, việc cấp phát một vùng nhớ lớn liên tục (dùng cho mảng) đôi khi không thực hiện được và chương trình cũng không báo lỗi. Bạn chú ý nhé.

bete
16-04-2005, 22:34
Cho tui góp 1 vài ý thô thiển nghen: Kijuto nghiêng về xài mảng (tốc độ), htbn_hoang nghiêng về danh sách liên kết (cấp phát bộ nhớ). Cả 2 cách đều có điểm mạnh và điểm yếu => mình có thể dung hòa cả 2 được không: xài danh sách liên kết của khối (mảng). Mình hiệu chỉnh kích thước khối cho thích hợp: quá nhỏ sẽ trở thành danh sách liên kết đơn thuần, quá lớn sẽ trở thành mảng. Tui nghĩ quản lý tập tin , cơ sở dữ liệu,.... đều cài đặt như vậy !?

-thân

Kijuto Riddle
17-04-2005, 12:45
to htbn_hoang:
tui không phản đối việc dùng bộ nhớ động. Có điều sử bài toán có sử dụng nhiều bộ nhớ hay không là do cách tiếp cận của mỗi người.


giả sử chúng ta cần lưu trữ một mảng 1000 số, mỗi số 4byte, vậy chúng ta cần 4000 byte

Cách cài đặt của Kijuto: để lưu trữ một số thập phân 1000 chữ số, nghĩa là số lớn nhất cần thao tác là 9999..... (1000 lần) = 10^1000. Cần một mảng bit có độ dài là x sao cho:
2^x >= 10^1000
-> x = log(cơ số 2) của 10^1000 = 1000 * log(cơ số 2) của 10 =(sấp xỉ) 3321(bit) = 415 byte
so sánh 415 byte với 4000 byte xem khác nhau thế nào.
ngoài ra, về tốc độ sử lý thì mới là vần đề. Kijuto xin post cả src của GreatInt.h lên:



/**
* @(#)GreatInt.h
* Copyright 2004,2005 Kijuto Riddle. No rights reserved.
*/

#ifndef _GREATINT_H
#define _GREATINT_H

#include <string.h>
#include <stdlib.h>
#include "Utils.h"
#include "alloc.h"
#include "krDef.h"


#define LONG_TYPE_SIZE 4 // size of Long type in byte, use for change the flatform, when Long type size is diffirent

#define STRING_LENGTH_MAX 10000

// #define SIZE_LONG 1038 // = 33216 bit nearly to 10000 char
#define SIZE_LONG 130 // = 33216 bit nearly to 10000 char

// size of GreatInt in long
const int MAX_LONG = SIZE_LONG-1; // max index of long array to descript GreatInt
const int SIZE_SHORT = SIZE_LONG<<1; // size of GreatInt in short = SIZE_LONG * 2
const int MAX_SHORT = (SIZE_LONG<<1)-1; // max index of short array to descript GreatInt
const int SIZE_BYTE = SIZE_LONG*LONG_TYPE_SIZE; // size of GreatInt in byte
const int MAX_BYTE = SIZE_LONG*LONG_TYPE_SIZE-1; // max index of byte array to descript GreatInt
const int SIZE_BIT = (SIZE_LONG*LONG_TYPE_SIZE)<<3; // size of GreatInt in bit = size in byte * 8
const int MAX_BIT = ((SIZE_LONG*LONG_TYPE_SIZE)<<3)-1; // max index of bit array to descript GreatInt


typedef struct GIntStruct{

unsigned long *data;

} gInt;

gInt* giMovL(gInt* const this,const long l);
void giPrintHex(const gInt* const this);

gInt* newGreatInt(void){
gInt* this = malloc(sizeof(gInt));
this->data = malloc(SIZE_LONG * sizeof (unsigned long));
return this;
}

gInt* newGreatIntL(long const l){
gInt* this = newGreatInt();
giMovL(this,l);
return this;
}

/************************ CONST************************************/

const gInt* giZERO;
const gInt* giONE;
const gInt* giTEN;
const gInt* giPOSINF;
const gInt* giNEGINF;

void gIntConst(void){
giZERO = newGreatIntL(0);
giONE = newGreatIntL(1);
giTEN = newGreatIntL(10);
giPOSINF = newGreatInt();
memset(giPOSINF->data,0xFF,MAX_LONG*4);
giPOSINF->data[MAX_LONG]=0x7FFFFFFF;
giNEGINF = newGreatIntL(0);
giNEGINF->data[MAX_LONG]=0x80000000;
}

/********************* END OF CONST********************************/

void giFree(gInt* const this){
free(this->data);
free(this);
}

gInt* giSet(gInt* this, gInt* const g){
if (this->data!=g->data)
free(this->data);
this->data = g->data;
return this;;
}

gInt* giMovL(gInt* const this,const long l){
memset(this->data,0,SIZE_BYTE); // zero fill the data array
this->data[0] = l;
return this;
}

gInt* giMov(gInt* const this,const gInt* const g){
memmove(this->data,g->data,SIZE_BYTE); // zero fill the data array
return this;
}

gInt* newGreatIntG(const gInt* const g){
gInt* this = newGreatInt();
giMov(this,g);
return this;
}

gInt* giShiftL(gInt* const this, int longCount){

register int i;

longCount %= SIZE_LONG;

if (!longCount) return this;

if (longCount>0){
i = MAX_LONG-longCount;
for (;i>=0;i--)
this->data[i+longCount] = this->data[i];
memset(this->data,0,longCount*LONG_TYPE_SIZE);
}else{
i = -longCount;
for (;i<SIZE_LONG;i++){
this->data[i+longCount] = this->data[i];
this->data[i]=0;
}
}
return this;
}

gInt* giShiftBit(gInt* const this, int bitCount){

register int i;
char b;

bitCount %= LONG_TYPE_SIZE<<3;

if (!bitCount) return this;

if (bitCount>0){
b = (LONG_TYPE_SIZE<<3) - bitCount;
for (i = MAX_LONG;i>0;i--){
this->data[i] <<= bitCount;
this->data[i] |= this->data[i-1] >> b;
}
this->data[0] <<= bitCount;
}else{
bitCount = -bitCount;
b = (LONG_TYPE_SIZE<<3) - bitCount;
for (i=0; i<MAX_LONG; i++){
this->data[i] >>= bitCount;
this->data[i] |= this->data[i+1] << b;
}
this->data[MAX_LONG] >>= bitCount;
}
return this;
}

gInt* giShift(gInt* const this, int bitCount){
giShiftL(this,bitCount/(LONG_TYPE_SIZE<<3)/**/);
return giShiftBit(this,bitCount);
}


gInt* giAdd(gInt* const this,const gInt* const g){

register unsigned long tmp = 0;
unsigned long hold;
register int i = 0;

for (;i<=MAX_LONG;i++){
tmp += this->data[i] & 0xFFFF;
tmp += g->data[i] & 0xFFFF;
hold = tmp & 0xFFFF;
tmp >>= 16;

tmp += this->data[i]>>16;
tmp += g->data[i]>>16;
hold |= (tmp & 0xFFFF)<<16;
tmp >>= 16;

this->data[i] = hold;
}
return this;
}

gInt* giNeg(gInt* const this){
register int i;
for (i=MAX_LONG;i>=0;i--){
this->data[i] = ~this->data[i];
}
return giAdd(this,giONE);
}

gInt* giSub(gInt* const this,const gInt* const g){
gInt* tmp = newGreatInt();
giMov(tmp,g);
giNeg(tmp);
giAdd(this,tmp);
giFree(tmp);
return this;
}

int giIsNeg(const gInt* const this){
return ((long)this->data[MAX_LONG])<0?1:0;
}

int giIsZero(const gInt* const this){
int i;
for (i=0; i<SIZE_LONG; i++)
if (this->data[i]!=0) return 0;
return 1;
}

int giIsPos(const gInt* const this){
return !giIsNeg(this) && !giIsZero(this);
}

int giCompare(const gInt* const this, const gInt* const g){
register int i = MAX_LONG;
if (giIsNeg(g) && !giIsNeg(this))
return 1;
if (giIsNeg(this) && !giIsNeg(g))
return -1;
for (;i>=0;i--){
if (this->data[i] > g->data[i])
return 1;
if (this->data[i] < g->data[i])
return -1;
}
return 0;
}

int giSign(const gInt* const this){
return giCompare(this,giZERO);
}

gInt* giMul(gInt* const this, const gInt* const g){

gInt* tmp = newGreatInt();
gInt* tt = newGreatInt();
gInt* gg = newGreatInt();
unsigned long lTmp;
register int j,i;
long it,jt;
int ft,fg;

int b=0;

giMov(gg, g);
giMov(tt, this);

if (giIsNeg(gg)){
giNeg(gg);
b = !b;
}
if (giIsNeg(tt)){
giNeg(tt);
b = !b;
}

for (i=MAX_LONG; i>0 && !tt->data[i]; i--); // find the first short != 0 from the left
lTmp = tt->data[i];
if (lTmp>>16)
ft = (i<<1)+1;
else
ft = (i<<1);
ft = min(ft,MAX_SHORT);

for (i=MAX_LONG; i>0 && !gg->data[i]; i--); // find the first bit = 1 from the left
lTmp = gg->data[i];
if (lTmp>>16)
fg = (i<<1)+1;
else
fg = (i<<1);

/**/
giMovL(this, 0);

for (i = ft; i>=0; i--)
for (j = min(fg,MAX_SHORT-i); j>=0; j--){
if (i&1)
it = tt->data[i>>1]>>16;
else
it = tt->data[i>>1] & 0xFFFF;

if (j&1)
jt = gg->data[j>>1]>>16;
else
jt = gg->data[j>>1] & 0xFFFF;

if (!it||!jt)
continue;
giMovL(tmp,it*jt);
giShift(tmp,(i+j)<<4);
giAdd(this,tmp);
}
giFree(tmp);
giFree(tt);
giFree(gg);
if (b)
return giNeg(this);
else
return this;
}

gInt* giDiv(gInt* const this, const gInt* const g){

gInt* tt=newGreatInt();
gInt* gg=newGreatInt();

unsigned long lTmp;
int i,j;
int delta;

int b=0;

giMov(gg, g);
giMov(tt, this);

if (giIsNeg(gg)){
giNeg(gg);
b = !b;
}
if (giIsNeg(tt)){
giNeg(tt);
b = !b;
}

if (giCompare(tt,gg)<0){
giFree(tt);
giFree(gg);
return giMovL(this,0);
}

for (i=MAX_LONG; i>0 && !tt->data[i]; i--); // find the first bit = 1 from the left
lTmp = tt->data[i];
for (j=0; j<32 && (lTmp>>=1); j++);
delta = (i<<5)+j; // delta = (index of first bit = 1) + 32

for (i=MAX_LONG; i>0 && !gg->data[i]; i--); // find the first bit = 1 from the left
lTmp = gg->data[i];
for (j=0; j<32 && (lTmp>>=1); j++);
delta -= (i<<5)+j; // delta = do lech giua hai ((vitri bit 1 dau tien) +32 )

// printf("delta = %d\n", delta);

giMovL(this, 0);

giShift(gg,delta); // giShift so chia to make both of them are nearest to equals


for (; delta>=0 && !giIsZero(tt); delta--,giShift(gg,-1)){
if (giCompare(tt,gg)<0) continue;
giSub(tt,gg);
this->data[delta>>5] |= 1<<(delta-((delta>>5)<<5)); // set the appropriate bit
}

giFree(tt);
giFree(gg);
if (b)
return giNeg(this);
else
return this;
}

gInt* giUp(gInt* const this, const int n){ // this *= 10^n
int i;
gInt* tmp=newGreatInt();
for (i=0; i<n; i++){
giShift(this, 1);
giMov(tmp, this);
giShift(this, 2);
giAdd(this, tmp);
}
giFree(tmp);
return this;
}

gInt* giDown(gInt* const this, const int n){
int i;
for (i=0; i<n; i++)
giDiv(this,giTEN);
return this;
}

gInt* giMod(gInt* const this, const gInt* const g){
gInt* b = newGreatInt();
giMov(b,this);
giDiv(b,g);
giMul(b,g);
giSub(this,b);
giFree(b);
return this;
}


int giStrParseType(const char* const str){
char s[STRING_LENGTH_MAX];
int i,j;
int len;

strcpy(s,str);
// strupr(s);

strTrimTrailing(s);

len = strlen(s);

// printf("\"%s\" -> %d\n",s,len);

if (s[0]=='0' && s[1]=='x'){
// '0x' is the first chars, the it must be the hex number
for (i=2; i<len; i++){
if (!((s[i]>='0' && s[i] <='9')
|| (s[i]>='A' && s[i]<='F')
|| (s[i]>='a' && s[i]<='f')
))
return false; // not a gInt
}
return -1; // hex? return -1
}else {
// else its must be the decimal
if (!((s[0]=='-')||(s[0]>='0' && s[0] <='9')))
return false;
for (i=1; i<len; i++){
if (!(s[i]>='0' && s[i] <='9'))
return false; // not a gInt
}
return 1; // decimal? return 1
}
}

private void giParseStrDec(gInt* const this, const char* const str){

int i;
gInt* tmp = newGreatInt();
int len = strlen(str);
int b = false;

giMovL(this,0);

for (i=0; i<len; i++){
if(str[i]=='-'){
b = true;
continue;
}
giUp(this,1);
giMovL(tmp,(long)(str[i]-'0'));
giAdd(this,tmp);
}
if (b)
giNeg(this);
giFree(tmp);
}
/**/
private void giParseStrHex(gInt* const this, const char* const str){

register int i = strlen(str)-1;
int j = 0;
int k = 0;
unsigned long hold=0;

if (i>SIZE_BIT<<2)
i = SIZE_BIT<<2;

for (;i>=0;i--){
if (str[i]<='9')
hold |= (str[i]-'0')<<j;
else
hold |= (str[i]-55)<<j;

if (j>=28){
if (k<SIZE_LONG){
this->data[k]=hold;
hold = 0;
k++;
}else
return;
j=0;
}else j+=4;
}
this->data[k]=hold;
for (k++;k<SIZE_LONG;k++){
this->data[k]=0;
}
return;
}

gInt* giParseStr(gInt* const this, char* const str){

int i= giStrParseType(str);

if (!i) return this;

strTrimTrailing(str);

if (i>0)
giParseStrDec(this,str);
else{
giParseStrHex(this,str+2);
}
return this;
}


void giPrint(const gInt* const this){
gInt* a=newGreatIntG(this);
gInt* b=newGreatInt();
char str[STRING_LENGTH_MAX]="";
int n=false;

if (!giCompare(this,giPOSINF)){
printf("[Positive Infinity]");
return;
}else if (!giCompare(this,giNEGINF)){
printf("[Negative Infinity]");
return;
}


if (giIsNeg(this)){
n = true;
giNeg(a);
}

do{
giMov(b,a);
giMod(a,giTEN);
giSub(b,a);
giDown(b,1);
str[strlen(str)]=a->data[0]+'0';

if (giIsZero(b)) break;

giMov(a,b);
giMod(b,giTEN);
giSub(a,b);
giDown(a,1);
str[strlen(str)]=b->data[0]+'0';

if (giIsZero(a)) break;

}while(true);
if (n)
str[strlen(str)]='-';
str[strlen(str)]='\0';
strrev(str);
printf(str);

giFree(a);
giFree(b);
}

void giPrintHex(const gInt* const this){
register int i=MAX_LONG;

for (;i>0;i--) if (this->data[i]!=0) break;

printf("0x");
for (;i>0;i--)
printf("%p,",this->data[i]);
printf("%p",this->data[0]);
}

#endif

htbn_hoang
18-04-2005, 10:44
"Tui nghĩ quản lý tập tin , cơ sở dữ liệu,.... đều cài đặt như vậy !?"

Thực ra thì không phải như vậy, trong CSDL hay quản lý tập tincos cung lượng lớn, người ta thường cài đặt cây nhị phân tìm kiếm hoặc (chủ yếu) cây m-nhánh, trong đó mỗi nút có kích thước bằng đúng kích thước của một sector trên đĩa (thường là 512 byte) vì mỗi lần đọc, ổ cứng phải đọc 1 sector. Việc xây dựng cây m-nhánh (đặc biệt khi yêu cầu cân bằng) là công việc phức tạp và tốn nhiều công sức, bù lại việc tìm kiếm sẽ đơn giản rất nhiều

bete
18-04-2005, 12:42
Thân gửi htbn_hoang: khi tui nói "cơ sở dữ liệu,.... đều cài đặt như vậy " thì tui không có ý nói về cấu trúc BTree+ mà ý tui muốn muốn nói về "data block size" của Oracle:

http://www.stanford.edu/dept/itss/docs/oracle/9i/server.920/a96524/c03block.htm

(khi cần thêm chỗ cho 1 byte thì CSDL sẽ không cấp phát thêm chỗ cho đúng 1 byte mà sẽ cấp phát nguyên 1 block (nhiều rows) => tuy có lãng phí bộ nhớ thiệt nhưng bù lại sẽ lợi về tốc độ nếu như bảng tăng liên tục (để giảm lãng phí bộ nhớ nhiều quá thì chọn kích thước khối cho thích hợp))

Tương tự khi tập tin cần thêm 1 byte thì sẽ không cấp phát thêm đúng 1 byte mà sẽ chơi nguyên 1 khối (hơi lãng phí chỗ nhưng bù lại truy xuất tuần tự nhanh hơn => chọn kích thước khối thích hợp để dung hòa)

Cấu trúc dữ liệu bạn xài cho tính toán số lớn cũng có thể làm tương tự: khi cần thêm 1 "int" thì xin thêm N "int" => khi tính toán sẽ làm trên 1 mảng con N phần tử thay vì duyệt N nút

(có gì sai sót xin các bạn chỉ giúp, cám ơn rất nhiều)

-thân

Pateheo
19-04-2005, 15:55
Cảm ơn anh Kijuto, nếu anh có thể gởi source bằng Java cho em được thì tốt quá, cách làm của anh rất sáng tạo.
Anh có thể gửi theo mail : phong.pathfinder@gmail.com
Cảm ơn anh nhiều.

Kijuto Riddle
22-04-2005, 12:48
source của GreatInt = Java thì không có, chỉ có source Fixed (số thực dấu chấm tĩnh) = Java thôi.
Bạn xem lại hình như email của bạn sai, email làm sao có dấu chấm nhỉ ???

LACA
22-04-2005, 13:09
co' thể gởi source java cho mình với được không?
binhminhtn@gmail.com
Thanks

Kijuto Riddle
23-04-2005, 11:43
Mượn tý đất diễn đàn cho tiện, khỏi gửi mail mọt gì cho phiền. Copy rồi paste vào file Fixed.java là xong. :)


package com.darKeRa.midp.math;

/**
* <p>Title: Class for fixed-point calculations in J2ME & J2SE applications (MIDP 1.0/CLDC 1.0 where float or double types are not available or J2SE to optimized the speed of Float calculation)</p>
* <p>Description: It makes fixed-point calculations via integer numbers</p>
* <p>Copyright: Kijuto Riddle Copyright (c) 2004</p>
* <p>Company: darKeRa</p>
* <p>License: GNU General Public License & Free for use only for non-commercial purpose</p>
* <p>You are free to use all or part of this class but don't forget to read and follow the GNU General Public License</p>
* <p>Please append my copyright information com.darKeRa.midp.math.Fixed (C) by Kijuto Riddle on ‘About’ screen of your product</p>
* <p>If you have web site please share this class for everyone.</p>
* <p>That's all, thank you!</p>
* @author Kijuto Riddle
* @version 2.03
*/

/**
* Fixed Point Math
* Kijuto Riddle
* Version 2.03
*
*
* Su dung 16 bit lam phan integer co dau, dau cua Fixed la dau cua integer
* (chu y dau khi Int == 0)
* Su dung 16 bit tiep theo la phan Fraction khong dau, gia tri Fraction = low16bit / 2^16
*
* val = 16 + 16 = 32 bit;
* dau cua val == dau cua Int == dau cua Fixed
*
* :: Version 2.0 changes:
* Don't use the construction methods but use assign methods
* Warning: The method assign(int vInt) replace by setData(int v)
* The method parseInt(int vInt) replace by assign(int vInt)
* Optimized the mul, mulBy, div, divBy method
* add pow(int p) method
* add sqrt() method
* bugs fixed and optimized toSring() method
*
*:: Version 2.02 changes:
* Replace the assign(int vInt, int vFrac) // keep it in the comments
* with assign(int vFracDiv, int vDiv)
* Fix the const define too ...
* Optimized the assign(int vInt, int vFracDiv, int vDiv)
* New ways to comment the usage of assign methods
* add int sign() method: return the sign of fixed
* add Fixed angleOptimize() method: optimize the angle value to (-Pi,Pi]
*
*:: Version 2.03 changes:
* Optimized the toString(): don't create the String Object, but return the string it self
*
* :: Version 2.04 changes:
* Optimized all methods :)
*
*/

final public class Fixed
{
final static public Fixed POSINF = new Fixed().assign(Short.MAX_VALUE,Short.MAX_VALUE-Short.MIN_VALUE);
final static public Fixed NEGINF = new Fixed().assign(Short.MIN_VALUE+1,Short.MAX_VALUE-Short.MIN_VALUE);
final static public Fixed ERROR = new Fixed().setData(NEGINF.val+1);
final static public Fixed SQRT2 = new Fixed().assign(1, 27146, 65536);
final static public Fixed SQRT3 = new Fixed().assign(1, 47976, 65536);
final static public Fixed PI = new Fixed().assign(3, 9279, 65536);
final static public Fixed ZERO = new Fixed();
final static public Fixed ONE = new Fixed().assign(1);
final static public Fixed E = new Fixed().assign(2, 47073, 65536);
final static public Fixed LN10 = new Fixed().assign(2, 19830, 65536);
final static public Fixed PIdiv2 = PI.div(2);
final static public Fixed PIdiv3 = PI.div(3);
final static public Fixed PIdiv4 = PI.div(4);
final static public Fixed PIdiv6 = PI.div(6);
final static public Fixed PIdiv8 = PI.div(8);
final static public Fixed PIdiv12 = PI.div(12);
final static public Fixed PImul2 = PI.mul(2);
final static public Fixed PImul4 = PI.mul(4);

public int val;

public Fixed(){
}

public Fixed setData(int d){
// :: this.val = v;
val = d;
return this;
}

/*public Fixed assign(){
// :: this = 0;
val = 0;
return this;
}/**/

public Fixed assign(int Int){
// :: this = Int.0
val = Int<<16;
return this;
}

/*public Fixed assign(int vInt, int vFrac)
{
// :: this = vInt + vFrac/0xFFFF
// Make sure that vFrac is positive and less than 2^16=65536=0xFFFF

if (vInt<0)
val = -(((-vInt)<<16) | (vFrac&0xFFFF));
else
val = (vInt<<16) | (vFrac&0xFFFF);
return this;
}/*/
public Fixed assign(int vFracDiv, int vDiv){
// :: this = 0 + vFracDiv/vDiv
// Make sure that:
// 0 < vDiv <= 2^16
// |vFracDiv| < 2^16=65536=0xFFFF
// |vFracDiv| < vDiv
if (vFracDiv<0)
val = -((((-vFracDiv)<<16)/vDiv)&0xFFFF);
else
val = ( (vFracDiv <<16)/vDiv)&0xFFFF;
return this;
}

public Fixed assign(int vInt, int vFracDiv, int vDiv){
// :: this = vInt + vFracDiv/vDic;
// Make sure that:
// 0 < vDiv <= 2^16
// 0 <= vFracDiv < 2^16=65536=0xFFFF
// vFracDiv < vDiv
if (vInt<0)
val = -(((-vInt)<<16) | (((vFracDiv<<16)/(vDiv))&0xFFFF));
else
val = (vInt<<16) | (((vFracDiv<<16)/(vDiv))&0xFFFF);
return this;
}

public Fixed assign(Fixed f){
// :: this = f;
val = f.val;
return this;
}

public Fixed shiftL(int i){
Fixed ret =new Fixed();
ret.val = val<<i;
return ret;
}
public Fixed shiftR(int i){
Fixed ret =new Fixed();
ret.val = val>>i;
return ret;
}

public Fixed beShiftL(int i){
val<<=i;
return this;
}
public Fixed beShiftR(int i){
val>>=i;
return this;
}

public Fixed shiftAdd(int l, int m){
Fixed ret =new Fixed();
ret.val = (val<<l) + (val<<m);
return ret;
}
public Fixed shiftSub(int l, int m){
Fixed ret =new Fixed();
ret.val = (val<<l) - (val<<m);
return ret;
}
public Fixed beShiftAdd(int l, int m){
val = (val<<l) + (val<<m);
return this;
}
public Fixed beShiftSub(int l, int m){
val = (val<<l) - (val<<m);
return this;
}

public int getInt(){
if (this.val<0)
return -((-val)>>16);
else
return (val>>16);
}

public int getFrac(){
return (val<0?-val:val)&0xFFFF;
}

public String toString(int nbp){
if (val==POSINF.val) return "Positive Infinity";
if (val==NEGINF.val) return "Negative Infinity";
if (val==ERROR.val) return "Error";
int vInt = this.getInt();
long vFrac = this.getFrac();
long LIMIT = Long.MAX_VALUE/10;

StringBuffer strBuff = new StringBuffer(nbp+5);

if ( val<0 && vInt==0 ) strBuff.append('-');
strBuff.append(vInt);
strBuff.append(".");

int i=0;

for(; i<nbp && (vFrac<LIMIT); i++)
{
strBuff.append((vFrac*=10)>>16);
vFrac &= 0xFFFF;
}

int len = strBuff.length();

for (int j=1; j<i && (strBuff.charAt(len-j)=='0'); j++)
strBuff.deleteCharAt(len-j);

return strBuff.toString();
}
public String toString(){
return toString(13);
}

public Fixed getNeg(){
// :: return -this
Fixed ret =new Fixed();
ret.val = -val;
return ret;
}
public Fixed beNeg(){
// :: this = -this;
val = -val;
return this;
}


public Fixed plus(Fixed f){
// :: return (this + f)
Fixed ret =new Fixed();
ret.val = val+f.val;
return ret;
}
public Fixed plus(int i){ ///////////////////////
// :: return (this + i)
Fixed ret =new Fixed();
ret.val = val+(i<<16);
return ret;
}

public Fixed add(Fixed f){
// :: this += f
val += f.val;
return this;
}
public Fixed add(int i){
// :: this += i;
val += i<<16;
return this;
}


public Fixed minus(Fixed f){
// :: return (this - f)
Fixed ret =new Fixed();
ret.val = val - f.val;
return ret;
}
public Fixed minus(int i){
// :: return (this - i)
Fixed ret =new Fixed();
ret.val = val-(i<<16);
return ret;
}

public Fixed sub(Fixed f){
val -= f.val;
return this;
}
public Fixed sub(int i){
val -= i<<16;
return this;
}


public Fixed mul(Fixed f){
Fixed ret =new Fixed();
ret.val = (int)((val*(long)f.val)>>16);
return ret;
}
public Fixed mul(int i){
Fixed ret =new Fixed();
ret.val = val*i;
return ret;
}

public Fixed mulBy(Fixed f){
val = (int)((val*(long)f.val)>>16);
return this;
}
public Fixed mulBy(int i){
val *= i;
return this;
}


public Fixed div(Fixed f){
Fixed ret =new Fixed();
ret.val = (int)((((long)val)<<16)/f.val);
return ret;
}
public Fixed div(int i){
Fixed ret =new Fixed();
ret.val = val/i;
return ret;
}

public Fixed divBy(Fixed f){
val = (int)((((long)val)<<16)/f.val) ;
return this;
}
public Fixed divBy(int i){
val /= i;
return this;
}


public Fixed pow(int p){
if (val==0) return new Fixed().assign(ZERO);
if (p==0) return new Fixed().assign(ONE);
if (p==1) return new Fixed().assign(this);
Fixed f = new Fixed().assign(this);
for (int i=p-1;i>0;i--)
f.mulBy(this);
return f;
}

public Fixed sqrt(){
if (val<0) return new Fixed().assign(ERROR);
if (val==0) return new Fixed().assign(ZERO);
if (val==ONE.val) return new Fixed().assign(ONE);

int sp = 0;
boolean inv = false;
Fixed a,b;
Fixed tmp = new Fixed();

if (val<ONE.val){
tmp = invert();
inv = true;
}else
tmp.assign(this);

while (tmp.val>(16<<16)){ //while (tmp.great(16)){
sp++;
tmp.val>>=4; //tmp.divBy(16);
}

a = new Fixed().assign(2);


for (int i=3; i>0; i--){ // change this number higher to more accurate, and vice versa
b = tmp.div(a);
a.add(b).val>>=1; //a.add(b).divBy(2);
}

while (sp-->0)
a.val<<=2; //a.mulBy(4);

if (inv)
a.beInvert();
return a;
}


public Fixed invert(){
return ONE.div(this);
}
public Fixed beInvert(){
return this.assign(ONE.div(this));
}


public Fixed abs(){
Fixed ret =new Fixed();
ret.val = val<0?-val:val;
return ret;
}
public Fixed beAbs(){
val = val<0?-val:val;
return this;
}


public int round(){
if (val>0)
return ( getFrac()>=0x8000?(getInt()+1):getInt() );
else
return ( getFrac()>=0x8000?(getInt()-1):getInt() );
}


public boolean isNegative(){
return val<0;
}
public boolean isPositive(){
return val>0;
}
public int sign(){
return val<0?-1:1;
}


/*public boolean great( Fixed f ){
return val>f.val;
}/**/
/*public boolean great( int i ){
return val>(i<<16);
}/**/

/*public boolean less( Fixed f ){
return val<f.val;
}/**/
/*public boolean less( int i ){
return val<(i<<16);
}/**/

/*public boolean equal( Fixed f ){
return val==f.val;
}/**/
/*public boolean equal( int i ){
return val==(i<<16);
}/**/


public Fixed angleOptimize(){
while ( val > PI.val )
sub(PImul2);
while ( val <= -PI.val )
add(PImul2);
return this;
}

public Fixed sin(){
while ( val > PI.val )
sub(PImul2);
if ( val < 0 ) return this.getNeg().sin().getNeg();
if ( val > PIdiv2.val ) return PI.minus(this).sin();
if ( val == PIdiv2.val ) return ONE;

Fixed result = new Fixed().assign(this);

Fixed m = this.mul(this).mulBy(this);
result.sub(m.div(6));

m.mulBy(this).mulBy(this);
result.add(m.div(120));

m.mulBy(this).mulBy(this);
result.sub(m.div(5040));

return result;
}

public Fixed cos(){
while ( val > PI.val )
sub(PImul2);
if ( val < 0 ) return this.getNeg().cos();
if ( val > PIdiv2.val ) return PI.minus(this).cos().getNeg();
if ( val == PIdiv2.val ) return ZERO;

Fixed result = new Fixed().assign(1);

Fixed m0 = this.mul(this);
result.sub(m0.shiftR(1)); //result.sub(m0.div(2));

Fixed m = m0.mul(m0);
result.add(m.div(24));

m.mulBy(m0);
result.sub(m.div(720));

return result;
}

public Fixed tan(){
Fixed c = cos();
Fixed s = sin();
if ( c.val == 0 )
if ( s.val < 0 )
return NEGINF;
else return POSINF;
return (s.divBy(c));
}

public Fixed toDeg(){
return this.mul(180).divBy(PI);
}
public Fixed toRad(){
return this.mul(PI).divBy(180);
}

/*public Fixed atan()
{
boolean signChange = false;
boolean invert = false;
int sp = 0;
Fixed x2,a,x = new Fixed().assign(this);

if (x.less(ZERO))
{
x.beNeg();
signChange = true;
}

if (x.great(ONE))
{
x.beInvert();
invert = true;
}

while(x.great(PIdiv12))
{
sp++;
a = x.plus(SQRT3);
a.beInvert();
x.mulBy(SQRT3);
x.sub(ONE);
x.mulBy(a);
}

x2 = x.mul(x);
a = x2.plus(new Fixed().assign(1,26790));
a = new Fixed().assign(0,36644).divBy(a);
a.add(new Fixed().assign(0,39525));
a.sub(new Fixed().assign(0,3382).mulBy(x2));
a.mulBy(x);
// process until sp=0
while(sp>0)
{
a.add(PIdiv6);
sp--;
}
if (invert) a = PIdiv2.minus(a);
if (signChange) a.beNeg();
//
return a;
}/**/
}

neverstop
24-04-2005, 15:17
sao các bạn không lưu vào 1 danh sách 1 chiều nhỉ (không cần 2 chiều). Mỗi phần tử là 1 integer, lưu 3 chữ số liên tiếp. Thực hiện các phép toán chỉ trên từng phần tử 1, sau đó hãy cộng dồn các số nhớ với nhau.

VD: số 12312310941413 sẽ được lưu giữ trong danh sách như sau:
413 -> 941 -> 310 -> 312 -> 12

Việc duyệt danh sách sẽ duyệt từ hàng đơn vị lên (chú ý, mỗi phần tử của danh sách chứa 1 hàng).

Pateheo
28-04-2005, 11:07
Em đã đọc qua code GreatInt của anh. Nhưng mà quả thực là khó hiểu vô cùng. Anh có thể nói sơ qua tư tuởng các phép xử lí cho em được không? Em cũng đã thử làm được bài toán trên nhưng với cấu trúc dữ liệu là một mảng char*. Tất nhiên với một số 1000 chứ số thì tốn mất 1000 byte. Điều khó xử lí trên bit là làm sao thực hiện phép chia? Chẳng lẽ cứ dịch trái hoài à?

Kijuto Riddle
28-04-2005, 20:01
Ờ, nếu mà chỉ đọc code thì cũng khó hiểu thật. Các phép toàn khác chắc không có vần đề gì, phép chia có kỹ thuật hơn lạ một chút, có thời gian Kijuto sẽ soạn và gửi cho bạn tài liệu thuật giải. Không biết phải dùng tài liệu kiểu gì để biểu diễn mấy công thức toán học đây, mình không rành sử lý văn bản lắm. :(

tinhthl
28-04-2005, 21:24
Đoạn code đơn giản nhất để làm bài tính toán trên số lớn đây:


#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#include <dos.h>
#include <ctype.h>

int ktrachuoi(char *s);
void chuanhoa(char *(*s));
int dau(char *(*s)); // xac dinh dau cua 2 chuoi so bat ki
int sosanh(char *s1,char *s2); // so sanh 2 chuoi so nguyen duong
char *tong(char *s1,char *s2); // chieu dai s1 <= s2
char *hieu(char *s1,char *s2); // voi s2 > s1 va chieu dai s1<=s2
char *tich1so(char *s1,char ic); // nhan 1 chuoi so nguyen duong voi 1 ky tu so
char *thuong(char *s1,char *s2,char *(*du)); // chia 2 so su dung phuong phap tru

char *cong(char *s1,char *s2);
char *tru(char *s1,char *s2);
char *nhan(char *s1,char *s2);
char *chia(char *s1,char *s2,char *(*du));
int sosanh2chuoiso(char *s1,char *s2);

void main()
{ clrscr();
char *stam;

do
{ fflush(stdin);
printf("Nhap so thu 1: "); gets(stam);
}while (ktrachuoi(stam)==0);
chuanhoa(&stam);
char *s1;
s1 = (char *)calloc(strlen(stam)+1,sizeof(char));
strcpy(s1,stam);

do
{ fflush(stdin);
printf("Nhap so thu 2: "); gets(stam);
}while (ktrachuoi(stam)==0);
chuanhoa(&stam);
char *s2;
s2 = (char *)calloc(strlen(stam)+1,sizeof(char));
strcpy(s2,stam);

char *kq;

kq = cong(s1,s2);
printf("Tong = %s\n",kq);
free(kq);

kq = tru(s1,s2);
printf("Hieu = %s\n",kq);
free(kq);

kq = nhan(s1,s2);
printf("Tich = %s\n",kq);
free(kq);

char *du;
kq = chia(s1,s2,&du);
if (kq!=NULL)
{ printf("Thuong = %s\n\tdu: %s\n",kq,du);
free(kq);
free(du);
}
if (kq==NULL)
printf("Khong the chia duoc !\n");

int ss;
ss = sosanh2chuoiso(s1,s2);
if (ss!=0)
printf("Chuoi so %d lon hon\n",ss);
else
printf("2 Chuoi nay bang nhau\n");

free(s1);
free(s2);

getch();
}

////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
int ktrachuoi(char *s)
{ int len;
if (!isdigit(s[0]) && s[0]!='+' && s[0]!='-')
return 0;
len=strlen(s);
for (int i=1;i<len;i++)
if (!isdigit(s[i]))
return 0;
return 1;
}

void chuanhoa(char *(*s))
{ int i=0;
int len;

if ((*s)[0]=='-' || (*s)[0]=='+')
i=1;
while ((*s)[i]=='0')
{ len=strlen(*s);
for (int j=i;j<len;j++)
(*s)[j]=(*s)[j+1];
}
if (i==0 && strlen(*s)==0)
strcpy((*s),"0");
if (i==1 && strlen(*s)==1)
(*s)[0]='0';
}

int dau(char *(*s))
{ int tam;
if ((*s)[0]=='-')
tam=0;
else
tam=1;
if ((*s)[0]=='-' || (*s)[0]=='+')
(*s)++;
return tam;
}

int sosanh(char *s1,char *s2)
{
int ss; // 0: s1=s2 1:s1>s2 2:s2>s1
int len1,len2;
len1=strlen(s1);
len2=strlen(s2);
if (len1<len2) return 2;
if (len2<len1) return 1;

ss=strcmp(s1,s2);
if (ss<0) return 2;
if (ss>0) return 1;
return 0;

}

// Tinh tong s1 va s2, tra ve chuoi tong
// voi chieu dai s1<s2
char *tong(char *s1,char *s2)
{ int i,itam,nho=0;
char c1[2],c2[2],*s=NULL,ctam[2];
int len1,len2;
len1=strlen(s1);
len2=strlen(s2);

// cap phat vung nho cho stam
char *stam;
stam = (char *)calloc(len2+2,sizeof(char));
s=stam+1;

// gan cho ky tu cuoi cua 2 chuoi tam la c1 va c2 la NULL
c1[1]='\0';
c2[1]='\0';

// chay het chieu dai cua so ngan la s1
for (i=len1-1;i>=0;i--)
{ c1[0]=s1[i];
c2[0]=s2[i+len2-len1];
itam=atoi(c1)+atoi(c2)+nho;
nho=0;
if (itam>=10)
{ nho=1;
itam%=10;
}
itoa(itam,ctam,10);
s[i+len2-len1]=ctam[0];
}

// chay tiep phan con lai cua s2
for (i=len2-len1-1;i>=0;i--)
{ c2[0]=s2[i];
itam=atoi(c2)+nho;
nho=0;
if (itam>=10)
{ nho=1;
itam%=10;
}
itoa(itam,ctam,10);
s[i]=ctam[0];
}

// gan vao cuoi chuoi s la NULL
s[len2]='\0';
// neu van con nho thi:
// 1. dua con tro s tro lui ve 1 char
// 2. gan so 1 vao vi tri dau tien cua chuoi
if (nho==1)
{ s--;
s[0]='1';
}

// Giai phong bo nho cu va cap phat bo nho moi cho kq
char *kq;
kq = (char *)calloc(strlen(s)+1,sizeof(char));
strcpy(kq,s);
free(stam);

return kq;
}

// Tinh hieu s1 va s2, tra ve chuoi hieu
// voi so s2 > s1 va chieu dai s1<=s2
char *hieu(char *s1,char *s2)
{ int i,itam,nho=0;
char c1[2],c2[2],ctam[2];
int len1,len2;
len1=strlen(s1);
len2=strlen(s2);

// cap phat vung nho cho s
char *s;
s = (char *)calloc(len2+1,sizeof(char));

// gan cho ky tu cuoi cua 2 chuoi tam la c1 va c2 la NULL
c1[1]='\0';
c2[1]='\0';

// chay het chieu dai cua so ngan la s1
for (i=len1-1;i>=0;i--)
{ c1[0]=s1[i];
c2[0]=s2[i+len2-len1];
itam=atoi(c2)-atoi(c1)-nho;
nho=0;
if (itam<0)
{ nho=1;
itam+=10;
}
itoa(itam,ctam,10);
s[i+len2-len1]=ctam[0];
}

// chay tiep phan con lai cua s2
for (i=len2-len1-1;i>=0;i--)
{ c2[0]=s2[i];
itam=atoi(c2)-nho;
nho=0;
if (itam<0)
{ nho=1;
itam+=10;
}
itoa(itam,ctam,10);
s[i]=ctam[0];
}

// gan vao cuoi chuoi s la NULL
s[len2]='\0';

// chu y, chua can free

return s;
}

char *tich1so(char *s1,char ic)
{
char c[2];
c[1]='\0'; c[0]=ic;
int so=atoi(c);
int len;
len=strlen(s1);

char *s,*stam;
stam = (char *)calloc(len+2,sizeof(char));
s=stam+1;

char cs1[2],ctam[2];
cs1[1]='\0';
int itam;
int nho=0;
// chay het chieu dai chuoi s1
for (int i=len-1;i>=0;i--)
{ cs1[0]=s1[i];
itam=atoi(cs1)*so+nho;
nho=0;
if (itam>=10)
{ nho=itam/10;
itam%=10;
}
itoa(itam,ctam,10);
s[i]=ctam[0];
}

// gan vao cuoi chuoi s la NULL
s[len]='\0';
// neu van con nho thi:
// 1. dua con tro s tro lui ve 1 char
// 2. gan so 1 vao vi tri dau tien cua chuoi
if (nho>0)
{ itoa(nho,ctam,10);
s--;
s[0]=ctam[0];
}

// Giai phong bo nho cu va cap phat bo nho moi cho kq
char *kq;
kq = (char *)calloc(strlen(s)+1,sizeof(char));
strcpy(kq,s);
free(stam);

return kq;
}

char *thuong(char *s1,char *s2,char *(*du))
{
char *s,*p,*stam;

s=(char *)calloc(2,sizeof(char));
strcpy(s,"0");
p=tru(s1,s2);
while (p[0]!='-')
{ // thuc hien dua p qua stam de tinh toan roi free(p)
stam = (char *)calloc(strlen(p)+1,sizeof(char));
strcpy(stam,p);
free(p);
// p tro den (s tang len 1), sau do dua p qua s roi free(p)
p=cong(s,"1");
s=(char *)realloc(s,strlen(p)+2);
strcpy(s,p);
free(p);

p=tru(stam,s2);
free(stam);
}
// tim phan du
(*du)=cong(p,s2);

// free(p) cua tru(s1,s2) neu khong vo vong lap
// hoac free(p) cua tru(stam,s2) neu da vo vong lap
free(p);

// tra ve s
return s;
}

////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
char *cong(char *s1,char *s2)
{
int dau1,dau2;
dau1=dau(&s1);
dau2=dau(&s2);

int ss;
ss=sosanh(s1,s2);

// cap phat vung nho cho stam
char *stam,*s;
if (ss==0 || ss==1)
stam = (char *)calloc(strlen(s1)+3,sizeof(char));
else
stam = (char *)calloc(strlen(s2)+3,sizeof(char));
s=stam+1;

// thuc hien tinh toan
char *p;
if (ss==1 || ss==0)
{ if (dau1==1)
{
if (dau2==1)
{ p=tong(s2,s1);
strcpy(s,p);
free(p);
}
else
{ p=hieu(s2,s1);
strcpy(s,p);
free(p);
}
}
else // dau1==0
{
if (dau2==1)
{ p=hieu(s2,s1);
strcpy(s,p);
free(p);
s--;
s[0]='-';
}
else
{ p=tong(s2,s1);
strcpy(s,p);
free(p);
s--;
s[0]='-';
}
}
}
else //ss==2
{ if (dau1==1)
{
if (dau2==1)
{ p=tong(s1,s2);
strcpy(s,p);
free(p);
}
else
{ p=hieu(s1,s2);
strcpy(s,p);
free(p);
s--;
s[0]='-';
}
}
else // dau1==0
{
if (dau2==1)
{ p=hieu(s1,s2);
strcpy(s,p);
free(p);
}
else
{ p=tong(s1,s2);
strcpy(s,p);
free(p);
s--;
s[0]='-';
}
}
}

// Giai phong bo nho cu va cap phat bo nho moi cho kq
char *kq;
kq=(char *)calloc(strlen(s)+1,sizeof(char));
strcpy(kq,s);
free(stam);

chuanhoa(&kq);
return kq;
}

char *tru(char *s1,char *s2)
{
int dau1,dau2;
dau1=dau(&s1);
dau2=dau(&s2);

int ss;
ss = sosanh(s1,s2);

// cap phat vung nho cho stam
char *stam,*s;
if (ss==1 || ss==0)
stam = (char *)calloc(strlen(s1)+3,sizeof(char));
else
stam = (char *)calloc(strlen(s2)+3,sizeof(char));
s=stam+1;

// thuc hien tinh toan
char *p;
if (ss==1 || ss==0) // Truong hop s2<=s1
{
if (dau1==1)
{
if (dau2==1)
{ p=hieu(s2,s1);
strcpy(s,p);
free(p);
}
else
{ p=tong(s2,s1);
strcpy(s,p);
free(p);
}
}
else // dau1==0
{
if (dau2==1)
{ p=tong(s2,s1);
strcpy(s,p);
free(p);
s--;
s[0]='-';
}
else
{ p=hieu(s2,s1);
strcpy(s,p);
free(p);
s--;
s[0]='-';
}
}
}
else // (ss==2) //Truong hop chieu s1<s2
{
if (dau1==1)
{
if (dau2==1)
{ p=hieu(s1,s2);
strcpy(s,p);
free(p);
s--;
s[0]='-';
}
else
{ p=tong(s1,s2);
strcpy(s,p);
free(p);
}
}
else // dau1==0
{
if (dau2==1)
{ p=tong(s1,s2);
strcpy(s,p);
free(p);
s--;
s[0]='-';
}
else
{ p=hieu(s1,s2);
strcpy(s,p);
free(p);
}
}
}

// Giai phong bo nho cu va cap phat bo nho moi cho kq
char *kq;
kq=(char *)calloc(strlen(s)+1,sizeof(char));
strcpy(kq,s);
free(stam);

chuanhoa(&kq);
return kq;
}

char *nhan(char *s1,char *s2)
{ int i;

int dau1,dau2;
dau1=dau(&s1);
dau2=dau(&s2);
int len2;
len2=strlen(s2);

char *s,*p,*stam;

stam=tich1so(s1,s2[0]);
s=(char *)calloc(strlen(stam)+2,sizeof(char));
strcpy(s,stam);
free(stam);

for (i=1;i<len2;i++)
{
strcat(s,"0");
stam=tich1so(s1,s2[i]);
p=cong(s,stam);
free(stam);
s=(char *)realloc(s,strlen(p)+2);
strcpy(s,p);
free(p);
}

// tra ve kq
if (dau1^dau2==1)
{ char *kq;
kq=(char *)calloc(strlen(s)+2,sizeof(char));
kq[0]='-';
strcat(kq,s);
free(s);
chuanhoa(&kq);
return kq;
}
chuanhoa(&s);
return s;
}

char *chia(char *s1,char *s2,char *(*du))
{
if (s2[0]=='0')
return NULL;

int dau1,dau2;
dau1=dau(&s1);
dau2=dau(&s2);
int len1,len2;
len1=strlen(s1);
len2=strlen(s2);

char *s,*p,*stam;
s[0]='\0';

//thuc hien tinh toan
s=(char *)calloc(1,sizeof(char));
s[0]='\0';
stam=(char *)calloc(len2+3,sizeof(char)); // 3 ky tu them la phan du, NULL va ky tu ke
int i=0;
(*du)=(char *)calloc(2,sizeof(char));
strcpy((*du),"0");
char ctam[2];
ctam[1]='\0';
while (i<len1)
{ stam[0]='\0';
strcat(stam,(*du));
free((*du));
if (i==0)
for (int j=0;(j<len2+1)&&(i<len1);j++,i++)
{ ctam[0]=s1[i];
strcat(stam,ctam);
}
else
{ ctam[0]=s1[i++];
strcat(stam,ctam);
}

chuanhoa(&stam);
p = thuong(stam,s2,&(*du));
s=(char *)realloc(s,strlen(s)+strlen(p)+2);
strcat(s,p);
free(p);
}
free(stam);

// tra ve kq
if (dau1^dau2==1)
{ char *kq;
kq=(char *)calloc(strlen(s)+2,sizeof(char));
kq[0]='-';
strcat(kq,s);
free(s);
return kq;
}
return s;
}

int sosanh2chuoiso(char *s1,char *s2)
{ int dau1,dau2;
dau1=dau(&s1);
dau2=dau(&s2);
if (dau1^dau2==1)
{ if (dau1==1) return 1;
if (dau2==1) return 2;
}
if (dau1==1)
return sosanh(s1,s2);
else
{ int tam;
tam = sosanh(s1,s2);
if (tam==1) return 2;
else if (tam==2) return 1;
return 0;
}
}

Pateheo
29-04-2005, 17:38
Mình chưa đọc kĩ phương pháp của bạn. Nhưng khi đọc sơ qua đoạn comment cho phép chia, thấy có nói là dùng phương pháp trừ để thực hiện phép chia.
Nếu mình cho một con số 12^999 trừ cho 2 thì sao? Nếu lặp thông thường thì đến đời nào mới xong? Bạn dùng cách gì vậy?

bete
29-04-2005, 19:51
Mình có thể thử giả lập phần cứng:

http://cch.loria.fr/documentation/IEEE754/patterson/slides.pdf
(chỉ cần coi mấy cái flowcharts)

http://www.google.com/search?hl=en&lr=&q=computer+architecture+multiplication+division

-thân

Pateheo
05-05-2005, 17:37
Anh Kijuto ơi! Anh có thể bỏ chút thời gian để môt tả phưuơng pháp xử lí trên bit bài GreatInt được không? Rất mong muốn được biết bí kíp của anh!

aaabbc
05-05-2005, 17:52
Mình cũng vừa gặp bài toán tạo 1 lớp mảng kiểu nguyên nhưng phải xử lí trên bit và đang kẹt cách xử lí . Mong được Kijuto chỉ giáo !

Kijuto Riddle
08-05-2005, 11:05
Mình hứa sau thứ 4 tới đây sẽ hoàn thành tài liệu gửi cho các bạn. Nhưng xin khất các bạn từ giờ cho đến thứ 4 tới là có việc gấp rút cần hoàn thành. Các bạn chịu khó chờ một chút. Khoảng thứ 5 là Kijuto sẽ gửi được tài liệu. Kijuto hứa.

tinhthl
10-05-2005, 19:09
Mình chưa đọc kĩ phương pháp của bạn. Nhưng khi đọc sơ qua đoạn comment cho phép chia, thấy có nói là dùng phương pháp trừ để thực hiện phép chia.
Nếu mình cho một con số 12^999 trừ cho 2 thì sao? Nếu lặp thông thường thì đến đời nào mới xong? Bạn dùng cách gì vậy?

int ktrachuoi(char *s); Hàm dùng để kiểm tra chuỗi nhập có đúng qui tắc số hay không, tức là: ký tự đầu có thể là ký tự số, dấu + hay dấu -, các ký tự còn lại thì chỉ có thể là ký tự số.

void chuanhoa(char *(*s)); Hàm dũng để chuẩn hóa ký tự số đã được nhập vào. Với hàm này thì chuỗi nhập vào sẽ bị thay đổi. Chú ý: phải đưa địa chỉ của con trỏ trỏ đến chuỗi s.

int dau(char *(*s)); Hàm này kiểm tra dấu của chuỗi s. Trả về 1 nếu dương, 0 nếu âm. Với hàm này con trỏ có thể s sẽ bị thay đổi. Chú ý: phải đưa địa chỉ của con trỏ trỏ đến chuỗi s.

int sosanh(char *s1,char *s2); Hàm này so sánh 2 chuỗi số nguyên dương. Trả về 1 nếu chuỗi s1 > s2, trả về 2 nếu chuỗi s2 > s1, trả về 0 nếu 2 chuỗi bằng nhau.

char *tong(char *s1,char *s2); Hàm này trả về con trỏ trỏ đến địa chỉ lưu trữ kết quả của phép tính cộng 2 số nguyên dương s1 và s2 với chiều dài của chuỗi s2 >= s1. Địa chỉ mà hàm này trả về đã được cấp phát bằng hàm calloc. Vì vậy, cần phải giải phóng bộ nhớ sau khi sử dụng xong kết quả này.

char *hieu(char *s1,char *s2); Hàm này trả về con trỏ trỏ đến địa chỉ lưu trữ kết quả của phép tính trừ 2 số nguyên dương s2-s1 với chiều dài của chuỗi s2 >= s1 và s2 phải lớn hơn s1. Địa chỉ mà hàm này trả về đã được cấp phát bằng hàm calloc. Vì vậy, cần phải giải phóng bộ nhớ sau khi sử dụng xong kết quả này.

char *tich1so(char *s1,char ic); Hàm này trả về con trỏ trỏ đến địa chỉ lưu trữ kết quả của phép tính nhân chuỗi số nguyên dương s1 với kí tự số ic. Địa chỉ mà hàm này trả về đã được cấp phát bằng hàm calloc. Vì vậy, cần phải giải phóng bộ nhớ sau khi sử dụng xong kết quả này.

char *thuong(char *s1,char *s2,char *(*du)); Hàm này trả về con trỏ trỏ đến địa chỉ lưu trữ kết quả của phép tính chia 2 chuỗi số nguyên dương s1 và s2. Địa chỉ mà hàm này trả về đã được cấp phát bằng hàm calloc. Vì vậy, cần phải giải phóng bộ nhớ sau khi sử dụng xong kết quả này.
Hàm này sữ dụng phương pháp “trừ dần” nên do đó, cần kết hợp với hàm chia để thực hiện phép chia nhanh hơn.
Ngoài ra, hàm này còn làm thay đổi chuỗi số dư . Con trỏ *du cũng cấn được giải phóng sau khi sử dụng. Chú ý: phải đưa địa chỉ của con trỏ trỏ đến chuỗi du.

char *cong(char *s1,char *s2); Hàm này trả về con trỏ trỏ đến địa chỉ lưu trữ kết quả của phép tính cộng 2 chuỗi số bất kỳ. Địa chỉ mà hàm này trả về đã được cấp phát bằng hàm calloc. Vì vậy, cần phải giải phóng bộ nhớ sau khi sử dụng xong kết quả này.

char *tru(char *s1,char *s2); Hàm này trả về con trỏ trỏ đến địa chỉ lưu trữ kết quả của phép tính trừ 2 chuỗi số bất kỳ s1-s2. Địa chỉ mà hàm này trả về đã được cấp phát bằng hàm calloc. Vì vậy, cần phải giải phóng bộ nhớ sau khi sử dụng xong kết quả này.

char *nhan(char *s1,char *s2); Hàm này trả về con trỏ trỏ đến địa chỉ lưu trữ kết quả của phép tính nhân 2 chuỗi số bất kỳ. Địa chỉ mà hàm này trả về đã được cấp phát bằng hàm calloc hoặc realloc. Vì vậy, cần phải giải phóng bộ nhớ sau khi sử dụng xong kết quả này.

char *chia(char *s1,char *s2,char *(*du)); Hàm này trả về con trỏ trỏ đến địa chỉ lưu trữ kết quả của phép tính chia 2 chuỗi số nguyên dương s1 và s2. Địa chỉ mà hàm này trả về đã được cấp phát bằng hàm calloc hoặc realoc. Vì vậy, cần phải giải phóng bộ nhớ sau khi sử dụng xong kết quả này.
Hàm này sữ dụng phương pháp “hạ và chia”, trong đó chia là ta sử dụng hàm thuong với chuỗi số bị chia s1 chỉ lớn hơn số chia s2 cao nhất là 1 ký số.
Ngoài ra, hàm này còn làm thay đổi chuỗi số dư. Con trỏ *du cũng cấn được giải phóng sau khi sử dụng. Chú ý: phải đưa địa chỉ của con trỏ trỏ đến chuỗi du.

int sosanh2chuoiso(char *s1,char *s2); Hàm này so sánh 2 chuỗi số bất kỳ. Trả về 1 nếu chuỗi số s1 > s2, trả về 2 nếu chuỗi số s2 > s1, trả về 0 nếu 2 chuỗi số này bằng nhau.

Kijuto Riddle
12-05-2005, 13:37
Đây, như đã hứa. Một tràng pháo tay cho những nỗ lực tuyệt vời trong việc vật lộn với trình sử lý văn bản của Kijuto. Có gì không đúng xin mọi người cứ feed back. :)

Pateheo
12-05-2005, 16:38
Vô cùng cảm ơn sự hào hiệp và nhiệt tình của Kijuto đã phẫu thuật cái Spririt ra khỏi GreatInt.. Giống hệt phong cách của bác sĩ Kijuto.Thanks for all!!!

Tuy mới xem qua bài của anh nhưng phải nói Kijuto có một hiểu biết tuyệt vời về vấn đề anh trình bày, không giống những người hay nổ bom ở diễn đàn này. Nếu được xin tôn anh làm đại sư huynh.

Kijuto Riddle
13-05-2005, 22:10
Revision 2 is out! Sửa rất nhiều lỗi trong revision 1. Mong mọi người không ngần ngại feedback. Địa chỉ email (có trong revision 2) KijutoRiddle@sourceforge.net :).

to Pateheo:
không nên nói như vậy, mọi người đã bỏ công để trả lời các câu hỏi của em, và thật tệ là em đã đáp lại sự nhiệt tình của họ như vậy. Hơn nữa, Kijuto không thích những câu nói bóng gió, vì mọi người đều có thể sẽ nghĩ rằng em đang nói về họ. Chính em sẽ là người thiệt thòi đầu tiên. Em có chắc là khi em post câu hỏi lên đây, mọi người sẽ nhiệt tình trả lời em như trước không. Cần phải suy nghĩ kĩ trước khi nói, nữa là post một bài lên forum.

neverstop
14-05-2005, 22:18
ủa, sao không down được thế?

Pateheo
15-05-2005, 23:01
Em đã đọc bài của anh Kijuto. Xin ghi nhận và rút kinh nghiệm cho những lần phát ngôn sau của mình. Sau khi post bài đó xong cũng cảm thấy hơi quá về lời nói. Tuy nhiên, đó là những ý nghĩ của em có sau khi từ một box khác trỏ ra. Xin nhấn mạnh rằng, pateheo không hề có ý gì với các bạn đã đóng góp nhiệt tình cho chủ đề này. Và có gì thật sự gây hiểu lầm và phật lòng các bạn, Pateheo xin chính thức được xin lỗivì câu nói của mình.Tuy nhiên, cần phải hiểu một điều, khi lên diễn đàn, tất cả thành viên rất đa dạng và họ đến với nhiều mức kiến thức khác nhau. Sẽ chẳng ai là người biết hết, dù là trong một chủ đề nhỏ. Vì vậy, ta không nên có thái độ khiêu khích hay có ý miệt thị sự hiểu biết của người khác. Mọi người lên đây đều có ý muốn học hỏi mà. Pateheo sở dĩ có câu nói đó vì những cảm giác như đã nói ở trên thôi. Một lần nữa, xin nói rằng mình hoàn toàn không có ý gì với mọi người trong chủ đề này, bởi vì với mọi người, minhg còn thiếu một lời cảm ơn chứ nói gì đến trách móc. Xin cảm ơn anh Kijuto về sự nhiệt tình của anh và lời khuyên chí lý.

xinh_gai
21-05-2005, 18:38
Mình cũng có post một bài về vấn để này và đã có cách giải nhưng hình như nó chỉ tính được số có vài nghìn chữ số thôi hay sao ấy
Mình chỉ là Newbie nên cách giải của mình cũng không cao siêu lắm,các bạn có thể tham khảo code và chương trình của mình tại thread này (mình chỉ làm với phép nhân,phép cộng,trừ,chia thì cách giải ũng tương tự) :
http://manguon.com/forum/forum_posts.asp?TID=39415&PN=1

codontinhdoi
20-11-2005, 13:04
mấy anh ơi có ai có code của bài tập này, nhưng mà dùng bằng phương pháp danh sách liên kết đơn ko ạ.
trong đó mỗi 1 node chỉ chứa 1 con số từ 0 - >9.
Mong mấy anh giúp đỡ

Qua_tao
20-11-2005, 21:47
Bác Kijuto ơi cho em hỏi tí cái chương trình greatint.h của bác có một số cái em không hiểu lắm.Ví như "krDef.h" là thư viện gì thế ạ ?

duyphian
22-11-2005, 16:48
Ngày sưa mình đã làm một chương trình để tính các số nguyên lớn. Với ý tưởng là chúng ta không dùng hệ cơ số 10 dể tính toán nữa mà dùng hệ cơ số lớn hơn ví du 100,1000,10000....... Tùy thuộc yêu cầu bài toán mà chọn cho phù hợp. Khi đó các phép tính với số nhỏ hơn cơ số sẽ được tính bình thường. còn các số lớn hơn cơ số sẽ được tính dự trên mảng chữ số. với mảng int cơ số tối đa sẽ là 10000. Với cách làm này chúng ta có thể tăng đựợc gấp nhiều lần về độ dài số, và tốc độ tính toán.
Hic làm cái này cũng lâu rồi không nhớ rõ la làm thế nào nữa nhưng mà viết Ý tưởng ra đây dể mọi người tham khảo

pulpcorn
11-05-2011, 20:44
cảm ơn anh Kiụto Riddle nhé!