PDA

View Full Version : Mỗi kỳ 1 lần. Có thể bạn chưa biết ?!



Huynh Phong
24-08-2004, 23:29
--------------------------------------------------------------------------------

Trong Pascal, có nhiều đoạn chương trình hơi na ná giống nhau, nhưng ta phải viết ra từng proc riêng biệt (do Pascal định kiểu mạnh). Ví như:
procedure SubW(W: Word; Var D:LongInt);
begin
       D := 2*W;
end;
Và trong chương trình chính, bạn khai báo:
Var   D1:LongInt;
       D2:Word;
begin
       SubW(10, D1); { chương trình không báo lỗi }
       SubW(10, D2); { chương trình báo lỗi Error 26: Type mismatch = không đúng kiểu }
end;
Để khắc phục, ta lại lập thêm 1 proc mới:
procedure SubN(N: Byte; Var D:Word);
begin
       D := 2*N;
end;
Khi đó, chương trình chính có dạng:
begin
       SubW(10, D1);
       SubN(10, D2);
end;
Cũng cùng một chức năng là lấy số kết qủa, nhưng phải lập tới 2 proc, điều này hao tốn thời gian và vô lý quá.
Bạn có biết: Pascal cho phép định nghĩa biến không kiểu.Trong ví dụ trên, ta có thể gộp chúng lại thành 1 proc duy nhất:
procedure Sub(Kieu:Word; Var D);
begin
       LongInt(D) := 2*Kieu;
end;
Pascal tự động gán kiểu cho D, nếu kết quả 2*Kieu=1 byte thì D sẽ có kiểu là byte, nếu 2*Kieu=2 byte thì D sẽ có kiểu là Word, Integer (tùy theo trường hợp)...

Chú thích:
Tham trị (W, N..) có kiểu bất kì theo nhu cầu chứ không nhất thiết phải là Byte hoặc Word. Ta có thể khai báo:
procedure Sub(s:String; Var D);
begin
       String(D) := s;
end;
================================================== ========
Mong nhận được sự hưởng ứng của các bạn.

lee_huynh306
25-08-2004, 09:34
hihi, nếu như đơn giản như vậy thì đâu cần gì phải làm thế cho nó cực,
mình sửa lại thế này bạn xem thử nhá.
function sub(n:word):longint;
tmp:longint;
begin
tmp:=2*n;
sub:=tmp;
end;
Bây giờ, giả sử bạn truyền tham số cho function là biến word, chắc chắn là bạn sẽ nhân được giá trị longint, khỏi phải bàn, còn nếu bạn truyền tham số là biến byte, thì kết quả sẽ nhận được chỉ là 1 word thấp của biến longint, nghĩa là mình có thể nhận được biến word bằng các lệnh sau:
ww:=word(lo(sub(30)));
mình chĩ đưa ra điều này để nhắc bạn rằng không phải lúc nào cũng nên dùng biến không định kiểu. Thông thường biến không định kiểu dùng cho các mảng không xác định có độ lớn thay đổi do người dùng định nghĩa ví dụ như procedure drawpoly() trong unit graph.
Mà bạn cũng không thể dùng typecasting với mục đích đó như trong proceudre này được:
procedure Sub(Kieu:Word; Var D);
begin
LongInt(D) := 2*Kieu;
end;
giả sử như bạn truyền tham biến là một biến word, khi gọi procedure trên sẽ không bị pascal than phiền gì cả nhưng kết quả cũng chỉ nhận được biến word mà thôi, nói tóm lại khi bạn có thể truyền vào đó bất kỳ biến nào, nhưng kết quả thu được sẽ không phải là longint mà chính là kiểu của biến bạn truyền vào.
Còn đây là cái sai trầm trọng của bạn
procedure Sub(s:String; Var D);
begin
String(D) := s;
end;
STRING là một từ khoá, không thể dùng trong tyepcasting được, bạn sẽ nhân được thông báo invalid typecasting ngay khi compile procedure này.Nếu muốn làm thế bạn chỉ có thể làm như sau:
procedure Sub(s:String; Var D);
type str=string;
begin
Str(D) := s;
end;
Tham trị (W, N..) có kiểu bất kì theo nhu cầu chứ không nhất thiết phải là Byte hoặc Word.
Không phải là tham trị, mà là tham biến, hãy phân biệt cho chính xác nhé.
Nói túm lại, bạn nên nghiên cứu lại việc này kỹ hơn.
Cảm ơn bạn đã đọc!

Huynh Phong
26-08-2004, 04:21
...Còn đây là cái sai trầm trọng của bạn
procedure Sub(s:String; Var D);
begin
String(D) := s;
end;
STRING là một từ khoá, không thể dùng trong tyepcasting được, bạn sẽ nhân được thông báo invalid typecasting ngay khi compile procedure này.Nếu muốn làm thế bạn chỉ có thể làm như sau:
procedure Sub(s:String; Var D);
type str=string;
begin
Str(D) := s;
end;
===========================================
Bạn lại hoang phí một biến cho việc khai báo Type Str=String nữa rùi. Tôi chắc chắn rằng dùng cách String(D):= s, thì chương trình không những chạy tốt, mà còn..., không tin bạn thử chạy và dịch chương trình này xem (tui có kèm theo phần TP7 cho tiện, bạn load về và sử dụng luôn nhé...dâng đến tận răng rùi!):

uses crt;
procedure StrS(NhapS:String; Var S);
begin String(S) := NhapS; end;
Var Nhap : String[80];
begin
ClrScr;
StrS(
#83#97#111#32#110#103#117#32#113#117#160#32+
#100#122#97#121#44#32#67#117#32+
#84#138#111#32#63#46#46,
Nhap
);
Writeln(Nhap);
Readkey;
end.
=============================================
Thực chất, ta dùng Typecas:
String(D) := S;
Là đã ngầm định rằng D có kiểu string, khi cho :=S thì D chiếm Length(s) byte. Hay có nghĩa là D:String[Length(s)];
Cái lợi trong việc dùng Typecas là chương trình sẽ tự động phân bố bộ nhớ cho các biến (cụ thể D) một cách hợp lý nhất, tiết kiệm nhất.

TurboPascal có cung cấp hàm SizeOf(<D>) để xem <D> chiếm bao nhiêu byte trong chương trình. Khỏi phải giải thích nhiều, bạn cứ thử cho từng trường hợp, xem rùi sẽ rõ.

lee_huynh306
26-08-2004, 06:52
mình không có điều kiện để kiểm tra, nhưng mình có thể nhớ rất rõ rằng trước đây mình đã thử chuyện này 1 lần, và kết quả thì mình đã nói rồi đó !!
Theo mình được biết thì từ khóa của pascal không được dùng cho bất kỳ mục đích nào khác, và string là một trong số đó.Còn nữa bạn ạ, str ko phải là một biến mà là 1 kiểu dữ liệu !!!
Nói túm lại, mình vẫn giữ lập trường.

Huynh Phong
27-08-2004, 22:45
Đúng là từ khóa của pas không được dùng cho bất cứ việc gì khác. Nhưng từ khóa cũng có nhiều lọai, ví dụ, bạn có thể phân chia:
1/ type, uses, const, absolute, forward, far, near...
2/ Integer, string, word, byte, char...
.........................
Rõ ràng, bạn thấy <1> là từ khóa dùng định nghĩa các kiểu, các implementation. Còn <2> là từ khóa dành cho các biến do ta định nghĩa. Như vậy, sơ qua thì bạn cũng thấy được chỗ khác biệt giữa chúng rùi.
Pascal sẽ bắt lỗi nếu như bạn type cast <1>, còn <2> thì free, vô tư... Bởi <2> thực chất cũng chỉ là do ta định nghĩa mà thôi. String cũng là 1 trong những số đó, nó được Pascal định nghĩa sẵn: type string = array[low(byte)..high(byte)] of char;
Tại sao bạn được phép viết Integer(D) mà không được quyền viết String(D) ?!!!. Trong khi Integer & String đều là các từ khóa được ta định nghĩa ? Integer(D) thì hợp lệ, còn String(D) bạn cho là không hợp lệ, không hợp lệ chỗ nào ? Hãy giải thích thử. Và điều quan trọng là, bạn có test thử chương trình vừa rùi của tui chưa ? Bạn nói không có điều kiện, tui không thể đồng ý với bạn được. Bởi bất kì ở nơi nào, bạn cũng có thể test thử chương trình đó, tui đã cẩn thận up bộ TP7 kèm theo rùi mà, bạn chỉ việc load về và sử dụng, không nên đổ cho hoàn cảnh nhé !
Giữ vững lập trường là 1 chuyện tốt, nhưng cũng còn tùy vào từng trường hợp đó bạn ạ!...

===============Kết thúc phần tranh luận tại đây===========================================

lee_huynh306
29-08-2004, 08:59
Bạn lại sai nữa rùi,
string không thể xếp vào 2 được.
String chẳng những là một kiểu dữ liệu mà còn là một từ khoá(từ khoá duy nhất chỉ về một kiểu dữ liệu), còn tất cả các kiểu dữ liệu khác được gọi ta kiểu dữ liệu chuẩn(hay tên chuẩn, và bạn có thể thoải mái định nghĩa lại.
Nói túm lại :
bạn có thể làm như sau :
word = record
loword,hiword:byte;
end;
nhưng không thể làm :
string =record
length:byte;
chars:array[1..255] of char;
end;
Còn mấy cái near,far,const,type.. đâu có phải là kiểu dữ liệu đâu mà typecast
Và mình cũng cảm ơn bạn đã gửi tp7 cho mình, mình đã kiểm tra là procedure sub(); của bạn có thể compile được nhưng đoạn chương trình sau là không :
var d:integer;
begin
string(d):='12345';
end;
Error 61 : Invalid Type Cast
Như vậy, là không phải mình sai nhé, và mình cũng phải công nhận là bạn cũng không sai.
Nè, oan cho tui nha, lần trước tui định download về test thử nhưng mà mạng như con rùa, download giữa chừng thì đứng lại mất tiu.
Lần này coi như hoà. Và mình cũng có câu đố cho bạn đây
type
word= packed record
lo,hi:byte;
end;
var i:word;
begin
i:=0;
writeln(i);
readln
end.
Đoạn mã trên là đúng hay sai? Tại sao ? Nếu sai phải chỉnh lại thế nào ?
Hihi,đây có thể là một chủ đề mới được đấy.

Huynh Phong
29-08-2004, 12:41
Bạn khai báo D là integer, vậy thì làm sao typecast string(D):='12345' cho được (bởi bạn đã gán cho D là integer rùi). Type cast chỉ dùng cho biến không định kiểu như ngay từ đầu tui đã nói.


type
word= packed record
lo,hi:byte;
end;
var i:word;
Còn bạn dùng kiểu gán i := 0. Bạn không thể gán cho biến i một giá trị nào đó mà không chỉ rỏ giá trị đó là thuộc trường nào.

Nếu bạn muốn gán:
i :=<K>.
Bạn phải khai báo:
K:word
Và phép gán : i := k là chấp nhận.

Bạn muốn bản thân i = 0 (có nghĩa là 2 trường của i đều =0). Bạn phải set giá trị vào 2 trường của nó:
i.Lo := 0; i.Hi := 0;
hay With I do begin Lo :=0; Hi :=0; end;
Và muốn lấy lại giá trị của chính bản thân i, bạn cũng phải thâm nhập vào trường i: Write(I.Lo); Write(I.Hi);

lee_huynh306
31-08-2004, 08:43
hihi, lầm rồi bạn ạ, bạn có thể hoàn toàn thoải mái khi typecast, bất kỳ biến thuộc loại nào (hình như loại trừ string, ko được thoải mái), không tin thì thử xem.
còn vấn đề mình đưa ra, không phức tạp như bạn nghĩ đâu, cũng không cần phải giải quyết dài dòng như thế, chỉ cần thay câu :
i:word; bằng câu i:system.word; là xong ngay.
Như vậy thì có thể thoải mái làm gì thì làm cái biến i.

Huynh Phong
01-09-2004, 03:57
Rùa ơi, nếu nhà ngươi vẫn cho là string không type cast được, thì ngươi hãy chứng minh đi, hành động thì sẽ hay hơn lắm lời. Còn ngươi không chứng minh được, chứng tỏ ngươi chỉ suy luận bậy bạ mà thôi. Tôi không chấp nhất những người chỉ chuyên suy luận bậy bạ.

Cái biến i ấy, ngươi đã cho nó thuộc về system: i : system.word; Hóa ra, cái type word=... ngươi vừa khai báo là là đồ thừa rùi !!, cái kiểu này, chẳng khác nào "ăn cơm nhà vác tù và hàng tổng", chỉ có kẻ rỗi hơi mới làm việc đó.

Giả sử tôi có 2 biến: i,j. Tôi khai báo thế này:
i : system.word; { kiểu word do system định nghĩa, nằm trong System.tpu }
j : word; {kiểu word vừa định nghĩa sau }
Thì đương nhiên, i sẽ có giá trị 0..65500 gì đó. Còn j sẽ có 2 trường, 1 là j.hi & 1 là j.lo và 2 trường này có kiểu byte. Rõ ràng giữa i và j, chúng khác nhau ngàn dặm.

Để chứng minh điều tôi nói, tôi sẽ làm 1 đoạn chương trình sau:

{========== UNIT ================== }
Unit Screen; interface
uses crt;
procedure ClrScr; implementation
procedure ClrScr; var Att: Byte;
begin
     Att := TextAttr;
     Textbackground(01); Crt.ClrScr; Writeln('Ban da dung ClrScr cua Screen...');
     TextBackGround(Att div 16); TextColor(Att mod 16);
end;
end.
{ ======== PROGRAM ==================== }
uses crt, screen; var ch:char; Color:Byte;
begin
     Color := TextAttr;
Repeat
     TextBackGround(Color div 16); TextColor(Color Mod 16);
     Writeln('an 1: dung ClrScr cua CRT');
     Writeln('an 2: dung ClrScr cua Screen');
     ch := Readkey; if ch=#0 then ch := Readkey;
     Case ch of
          '1' : Crt.ClrScr;
          '2' : ClrScr;
     end;
Until Ch in[#27,#13];
end.
{ ========== end of file ============== }
Trong Unit CRT có proc ClrScr, trong Unit Screen cũng có proc ClrScr. Vậy nếu tôi chẳng nói rõ là dùng ClrScr của cái nào thì mặc nhiên chương trình sẽ dùng cái ClrScr của unit được khai báo sau. Nghĩa là nếu đoạn chương trình của tôi như thế này:

     uses Screen, CRT;
     ..................
     ClrScr;
Thì chương trình mặc nhiên sẽ dùng ClrScr của CRT. ngược lại, nếu:

     Uses CRT, SCReen;
     ...............
     ClrScr;
Thì chương trình lại mặc nhiên ClrScr là của Screen.

Nhưng nếu tôi chỉ rõ nên dùng ClrScr của Unit nào thì chương trình sẽ dùng ClrScr của unit đó:
     Screen.ClrScr;
     CRT.ClrScr;

Như vậy, cách khai báo cái biến i của ngươi:
     i:system.word;

thì đã chỉ rõ là dùng kiểu word của system <SAI LAM CUA NGUOI LA SU NGO NHAN> ngươi có thể xóa bỏ đoạn khai báo { type = packed record.... } mà cũng không ảnh hưởng gì đến chương trình.
Nói ít, hiểu nhiều...

lee_huynh306
02-09-2004, 07:19
Trời ạ, chẳng hiểu gì về điện, ai bảo cái record đó không có tác dụng
Cứ xách nó ra mà typecast thế là lấy được byte thấp và byte cao của word rùi. Có thế cũng bắt bẽ, còn nữa, tui đưa ví dụ ra là để minh họa chứ không nhằm mục đích khác nên đưa ra đơn giản thôi, ai biểu hiểu cao siêu quá rồi nói thừa thiếu này nọ, còn cái vụ typecast, cấm cãi nữa, nghe chưa?Tốt nhất là close cái topic này đi.

Huynh Phong
22-09-2004, 04:45
Oh, no, no!....No. Không nên close topic này, hôm nay tôi lại có 1 chiêu khác để các bạn mới làm quen với kiểu Record con trỏ trong Pascal tham khảo. Thông thường, khi mới bắt đầu làm quen với mảng động, bạn dễ bị mắc những lỗi sau:
- Thiếu vùng nhớ Heap.
- Giải phóng bộ nhớ không hết.
- Giải phóng bộ nhớ bị lỗ hổng. (Memavail<MaxAvail).
- Con trỏ truy cập đến vùng NIL hoặc ngoài Heap.
- ............
Nhiệm vụ của bạn là tìm lấy một giải thuật ngắn gọn, hiệu quả mà tránh được các sai sót đó.

==========================================
Giả sử, tôi có một Record word sau:
Type
      WordPtr = ^WordRec;
      WordRec= Record
                        W: word;
                        Ne xt: WordPtr;
                     End;
Trong chương trình, tôi dùng uses crt & khai báo:
var  soTien, soTien1, soTien2 : WordPtr;
      Quit    : Char;
      x, y    : byte;
begin
      gotoxy(01,01); Write('Nhap so tien:');
      x := WhereX;
      y := WhereY;
      Quit := #0;
      soTien1 := nil;
      soTien2 := nil;
Repeat
      if MemAvail<SizeOf(soTien) then begin Quit := #1; Break; end;
      gotoxy(x,y);
      New(soTien); { thuê o nhớ }
      Readln(soTien^.W); { nhập dữ liệu vào }

      { đoạn lệnh nối danh sách, kiểu first in first out :FIFO }
      soTien^.next := nil;
      if soTien1<>nil then soTien2^.next := soTien else soTien1 := soTien;
      soTien2 := soTien;      
      { đoạn lệnh thoát khỏi chương trình }
      Write('Thoat chua (T/K)?'); Quit := Readkey;
      gotoxy(01, WhereY); ClrEol;
Until Quit in ['t','T'];
      { Nếu heap không đủ thì thông báo }
      if Quit =#1 then
      begin
            Writeln;
            Writeln('Error Heap: Out of memory!');
      end;
end;
========================================
Kiểu FIFO có nghĩa là cái nào vào trước thì lấy ra trước. Trong proc trên, nếu bạn muốn hiển thị lại danh sách đã nhập theo thứ tự thì bạn có thể làm như sau:
      soTien := soTien1;
      While soTien<>nil do
      begin
            Writeln(soTien^.W);
            soTien := soTien^.next; { soTien bây giờ lại dịch chuyển về phần tử kế tiếp }
      end;
Người ta gọi kiểu liên kết này là liên kết 1 chiều hay đơn chiều. Chúng ta còn có kiểu liên kết đa chiều nữa (tới, lui, trái, phải).

Huynh Phong
22-09-2004, 05:22
<PHÁT TRIỂN DANH SÁCH LIÊN KẾT 1 CHIỀU THÀNH 2 CHIỀU >
Chẳng phải ngẫu nhiên mà cái Record của tôi có thành phần tên "Next", tôi cốt ý khai báo như vậy để dễ dàng giới thiệu cái danh sách liên kết 2 chiều này.
Liên kết 2 chiều, có nghĩa là con trỏ danh sách vừa có thể trỏ đến phần tử trước nó, vừa có thể trỏ vào phần tử đứng sau nó. ví dụ, con trỏ đang ở vị trí phần tử 15:

..... 14 [15] 16 ..... (CT1)
nếu ta cho trỏ (CT1) trỏ về trước thì sẽ là ........ [14] 15 16 ..........
ngược lại, nếu ta cho trỏ về sau, thì sẽ là .......... 14 15 [16] ........
      Để làm được điều này, bạn phải khai báo:
Type
      wordRec = Record
                        W : Word;
                        ne xt : wordPtr;
                        ba ck : wordPtr; { thêm con trỏ trỏ lui }
                     end;
Và trong đoạn lệnh nối danh sách, bạn thêm :
      soTien^.next := nil;
      sotien^.back := soTien2;
      if soTien1<>nil then soTien2^.next := soTien else soTien1 := soTien;
      soTien2 := soTien;

Bây giờ, bạn có thể truy cập thẳng danh sách mà không cần cho soTien := soTien1 nữa.
      while soTien <> nil do
      begin
            writeln(soTien^.W);
            soTien := soTien^.back; { lui về trước, CT1 từ 15 -> [14] }
      end;
Danh sách 2 chiều rất có ích trong chương trình viết về Open hoặc Save as.. (dò tìm thư mục, file...)

======================================

Huynh Phong
22-09-2004, 05:37
<THUẬT GIẢI GIẢI PHÓNG Ô NHỚ CHO BIẾN ĐỘNG DANH SÁCH LIÊN KẾT>
Sau khi không còn dùng soTien nữa, bạn giải phóng ô nhớ bằng cách:

1. Giải phóng theo kiểu "cái nào thuê trước thì bỏ trước" :
      soTien := soTien1;
      while soTien<> nil do
      begin
            soTien1 := soTien^.next;
            Dispose(soTien);
            soTien := soTien1;
      end;
2. Giải phóng theo kiểu "cái nào vào sau thì bỏ trước", cái này chỉ áp dụng được cho danh sách liên kết 2 chiều:
      soTien := soTien2;
      while soTien<>nil do
      begin
            soTien2 := soTien^.back;
            dispose(soTien);
            soTien := soTien2;
      end;

======================================

Huynh Phong
22-09-2004, 05:55
Sau khi cả trăm lần thử nghiệm, hết giải thuật của ông này đến giải thuật của bà kia dzìa danh sách liên kết con trỏ, cuối cùng tôi cảm thấy rằng đây là kiểu liên kết hay nhất, gọn nhất mà hiệu quả nhất. Tôi chắc mẩm rằng (hoặc có thể), chưa có một quyển sách nào viết giải thuật liên kết danh sách hoặc giải phóng biến động theo kiểu thế này. Hi vọng một ngày gần đây nó sẽ được xuất hiện trong sách dạy Pascal.
================== HP ================================

Huynh Phong
30-09-2004, 05:34
TỈ LỆ % TRONG THAO TÁC FILE

Bạn đang viết các chương trình về thao tác tệp như Copy, Paster, Creat file...Nếu bạn muốn cho chtrình làm việc này 1 cách âm thầm thì tôi không có gì để nói.

Thế nhưng, nếu muốn chương trình được đẹp hơn, rỏ ràng sáng sủa hơn thì theo kinh nghiệm của tôi, cách hay nhất là bạn tạo ra 1 box mà trong đó nó hiển thị chi tiết liên quan đến file thao tác (như tên file, đường dẫn, các thuộc tính, size...) đồng thời, hiển thị cái tỉ lệ phần trăm để cho người dùng biết chương trình thao tác đến đâu trong tệp.

Về kiểu dáng Box, chung quy box sẽ có 4 tọa độ, mà trong đó ta chỉ cần biết 2 tọa độ là vẽ được: tọa độ trên trái (x1,y1), tọa độ dưới phải (x2,y2).

Trong bài viết này, tôi chỉ đề cập đến phần SIZE , bởi phần này liên quan đến việc thu lấy tỉ lệ %.

Giả sử, bạn đang thao tác 1 file có size = 400MB, bạn muốn chương trình hiển thị tỉ lệ trong lúc thao tác tệp bằng cả 2 cách: dùng thanh cuốn ngang scroll & hiển thị tỉ lệ phần trăm dạng số nằm ở giữa.

Để tìm độ lớn của tệp F, bạn dùng hàm:
var Sz: LongInt;
                        Sz := FileSize(F);

Để tìm vị trí thao tác tệp (vị trí con trỏ tệp F), bạn dùng hàm:
var Ps: LongInt;
                        Ps := FilePos(F)

Tỉ lệ giữa Ps và Sz chính là tỉ lệ phần trăm (%) mà bạn mong muốn:
                        Ra tio := 100*Ps/Sz;

Trong việc tạo thanh cuốn, bạn muốn tìm tọa độ vị trí cuốn tương ứng với Ps, bạn làm như sau:
var scroll, k: Byte;
                        sc roll := x1+ Round((x2-x1)*Ps/Sz);
Và vẽ thanh cuốn:
                        fo r k := x1 to scroll do
                        be gin
                                 gotoxy(k, y2); Write(#219); { #219 kí tự vẽ box }
                        en d;
Bạn thấy khúc chương trình này như thế nào, hoàn hảo chưa ? Ban đầu tôi cho chạy thử với các tệp nhỏ (khỏang dưới 1MB) thì nó rất tuyệt, không phạm một lỗi nào cả, thế nhưng, những tệp trên 1MB thì giá trị của scroll lại không còn đúng nữa, mặc dù scroll được khai báo là byte, nhưng nó có thể mang số âm đấy !!! LỖI NGAY ĐÂY.

Tôi mướt mồ hôi để tìm cách khắc phục cái lỗi kì quặc này, hết chuyển scroll từ byte sang integer, sang word, longint... đến type cast, thế mà vẫn không xong dzới nó, vẫn có thể là giá trị âm. Hiện tượng này không thể xem là tràn số được, bởi giá trị scroll tính toán theo lý thuyết không thể nào hơn x2 được. Vậy đây là lỗi gì ?!...

BẠN CÓ BIẾT KHÔNG, ĐƠN GIẢN BẠN CHỈ VIỆC TÌM CÁCH CHUYỂN GIÁ TRỊ X1, X2 TỪ DẠNG BYTE -> REAL LÀ ĐƯỢC.

                        sc roll := x1+ Round((x2-x1)*Ps/Sz);
Bạn hãy viết lại:
                        sc roll := x1+ Round( (x2/1-x1/1)*Ps/Sz );
Thế là OK, scroll mãi mãi không còn là số âm nữa.
        
        
        

lee_huynh306
30-09-2004, 18:45
sc roll := x1+ Round((x2-x1)*Ps/Sz);
Bạn quên một điều là kiểu longint là một kiểu 4 bytes có dấu, mà khi dos trả về là kiểu 4 bytes không dấu, vì thế nếu bạn sử dụng một file cỡ 4GB chẳng hạn thì giá trị mà filesize(f) trả về sẽ là -1 (?!) và lúc này thì scroll sẽ là số âm nếu filepos <= 2 GB.
còn tổng quát hơn, khi sz > 2GB và ps < 2GB thì scroll < 0.
Nhưng khi 1MB < filesize(f) thì mình pó toàn thân.

Huynh Phong
30-09-2004, 19:33
sc roll := x1+ Round((x2-x1)*Ps/Sz);
Bạn quên một điều là kiểu longint là một kiểu 4 bytes có dấu, mà khi dos trả về là kiểu 4 bytes không dấu, vì thế nếu bạn sử dụng một file cỡ 4GB chẳng hạn thì giá trị mà filesize(f) trả về sẽ là -1 (?!) và lúc này thì scroll sẽ là số âm nếu filepos <= 2 GB.
Tôi không có dịp để thử file >1GB, { máy không cài }. Nhưng nếu dưới 1GB thì tôi đã thử nhiều. Tôi cũng cho in ra kết quả filePos(F) những file lớn, và hơn thế nữa, tôi cũng cho in ra kết quả của Ratio (= 100*FilePos(F)/SZ ). Những kết quả này hiển thị đúng. Thế nhưng khi cho thêm giá trị (x2-x1)*... vào thì chúng lại cho số âm (bởi vậy tôi mới phát hiện được là lỗi ngay ở điểm này).


Nếu (x2/1) sẽ đổi từ kiểu số nguyên sang kiểu số thực thì liệu rằng mình có thể viết
sc roll := x1+ Round( (x2-x1)/Sz*Ps);
được không (làm phép chia trước phép nhân) ????
Tôi cũng đã hoán chuyển như bạn nghĩ, nhưng vẫn không được bạn ạ.

Nhân dịp có 1 thành viên nhờ tôi về mấy vấn đề số nguyên tố đối xứng (đối xứng : 11, 121, 123321...). Trong đoạn chương trình, tôi có sử dụng con trỏ liên kết danh sách 2 chiều và tỉ lệ %. Tôi post lên đây, có thể bạn tham khảo thử.
 
 

bete
30-09-2004, 21:37
Thân gửi HuynhPhong:

Hiện tượng này không thể xem là tràn số được, bởi giá trị scroll tính toán theo lý thuyết không thể nào hơn x2 được. Vậy đây là lỗi gì ?!...

Tui nghĩ đây là tràn số đó chớ:

sc roll := x1+ Round((x2-x1)*Ps/Sz);

x2 > x1 => (x2-x1) > 1 => (x2-x1)*Ps > Ps => có khả năng tràn lắm chứ !?

------------------------------------------------------------

sc roll := x1+ Round( (x2/1-x1/1)*Ps/Sz );

Nếu (x2/1) sẽ đổi từ kiểu số nguyên sang kiểu số thực thì liệu rằng mình có thể viết

sc roll := x1+ Round( (x2-x1)/Sz*Ps);

được không (làm phép chia trước phép nhân) ????

-thân