Lỗi Overflow khi chạy function

Liên hệ QC

kyo

Nguyễn Khắc Duy
Thành viên danh dự
Tham gia
4/6/06
Bài viết
901
Được thích
2,714
Chào mọi người,

kyo có 1 tình huống bị lỗi mà không hiểu vấn đề tại sao muốn nhờ mọi người giúp đỡ. Với đoạn code dưới đây thì kyo gặp lỗi Overflow

Mã:
Function tiendien(sodien As Double) As Double

If sodien <= 50 Then
    tiendien = sodien * 1000
Else
    tiendien = 50 * 1000 + (sodien - 50) * 2000
End If

End Function

Nhưng khi sửa 50 * 1000 thành 50000 thì code vẫn chạy như bình thường.

Mọi người giải thích giúp kyo với. Cảm ơn mọi người nhiều.
kyo.
 
Chào mọi người,

kyo có 1 tình huống bị lỗi mà không hiểu vấn đề tại sao muốn nhờ mọi người giúp đỡ. Với đoạn code dưới đây thì kyo gặp lỗi Overflow

Mã:
Function tiendien(sodien As Double) As Double

If sodien <= 50 Then
    tiendien = sodien * 1000
Else
    tiendien = 50 * 1000 + (sodien - 50) * 2000
End If

End Function

Nhưng khi sửa 50 * 1000 thành 50000 thì code vẫn chạy như bình thường.

Mọi người giải thích giúp kyo với. Cảm ơn mọi người nhiều.
kyo.
Anh không hiểu bản chất vấn đề, nhưng có thể nó có liên quan đến kiểu dữ liệu. Em thay 50 bởi 50.0 (hay 50#) thì code chạy bình thường.
 
Upvote 0
Chào mọi người,

kyo có 1 tình huống bị lỗi mà không hiểu vấn đề tại sao muốn nhờ mọi người giúp đỡ. Với đoạn code dưới đây thì kyo gặp lỗi Overflow

Mã:
Function tiendien(sodien As Double) As Double

If sodien <= 50 Then
    tiendien = sodien * 1000
Else
    tiendien = 50 * 1000 + (sodien - 50) * 2000
End If

End Function

Nhưng khi sửa 50 * 1000 thành 50000 thì code vẫn chạy như bình thường.

Mọi người giải thích giúp kyo với. Cảm ơn mọi người nhiều.
kyo.
anh thử bỏ nó vào dấu ".."
Function Tiendien(Sodien As Long) As Long

If Sodien <= "50" Then
Tiendien = Sodien * "1000"
Else
Tiendien = "50" * "1000" + (Sodien - "50") * "2000"
End If

End Function
 
Upvote 0
Khả năng VB đoán 10 và 5000 là kiểu short giới hạn đến 32767 nên kết quả ra 50000 bị overflow. Để tránh lỗi này bạn có thể dùng 10& để VBA chuyển sang kiểu long. Nếu chuyển sang dạng text sẽ chậm hơn.
 
Upvote 0
Máy tính của mình tới số này thì bị lỗi.
PHP:
Sub vidu1()
    Dim a As Variant
    a = 49 * 669
End Sub
Chuyện sai số con Toán này chắc có hai anh biết. :D
 
Upvote 0
Đôc đáo gớm nhỉ.

Không chắc ăn cho lắm mặc dù trường hợp này không bị sao, gõ là 50.0 * 100000.0 chẳng hạn
Hehe em chưa thử cứ nghĩ cho nó vào dạng chuỗi chắc sẽ không bị giới hạn. Mà không biết được không nữa
 
Upvote 0
Cái này cho bài #1:
PHP:
Function tiendien(ByVal sodien As Double) As Double
    If sodien <= 50 Then
        tiendien = sodien * 1000
    Else
        tiendien = 50 * CDbl(1000) + CDbl(sodien - 50) * 2000
    End If
End Function
 
Upvote 0
Cái này cho bài #1:
PHP:
Function tiendien(ByVal sodien As Double) As Double
    If sodien <= 50 Then
        tiendien = sodien * 1000
    Else
        tiendien = 50 * CDbl(1000) + CDbl(sodien - 50) * 2000
    End If
End Function
Chỉ cần sửa 50 * 1000 bởi 50.0 * 1000 là đã chạy được rồi.
 
Upvote 0
Đôc đáo gớm nhỉ.

Không chắc ăn cho lắm mặc dù trường hợp này không bị sao, gõ là 50.0 * 100000.0 chẳng hạn
Nếu có 50.0 sẽ chuyển sang double không bị lỗi. Nếu tính kiểu số nguyên thì dùng 50& hoặc clng(50) hoặc cint(50), số 10000 và tích tự chuyển kiểu theo.
 
Upvote 0
Upvote 0
Thực chất thì việc sử dụng CDbl hay gõ 50.0 thì cũng cùng một mục đích là để anh chàng VBA hiểu rằng "nó là một số thực" và tính toán theo kiểu của số thực thôi mà
Vậy tức là số 50 không phải là số thực?
Còn số 50.0 mới là số thực?

gõ 50.0 rõ ràng là phải gọn hơn CDbl(50) hay CDbl(1000).
Mình không dám tin vậy đâu, nhất là bài của các anh ních màu xanh lá.
 
Upvote 0
Thực chất thì việc sử dụng CDbl hay gõ 50.0 thì cũng cùng một mục đích là để anh chàng VBA hiểu rằng "nó là một số thực" và tính toán theo kiểu của số thực thôi mà, gõ 50.0 rõ ràng là phải gọn hơn CDbl(50) hay CDbl(1000).
Một cais là convert một cái là trwcj tiếp.
Bài đã được tự động gộp:

Gõ là 50.0 vba sẽ chuyênn thành 50# thì phái.
 
Upvote 0
Khả năng VB đoán 10 và 5000 là kiểu short giới hạn đến 32767 nên kết quả ra 50000 bị overflow. Để tránh lỗi này bạn có thể dùng 10& để VBA chuyển sang kiểu long. Nếu chuyển sang dạng text sẽ chậm hơn.
Nó không hề đoán. Luật hằng số literals được nó định là:
Số có ký tự chỉ rõ loại: theo loại đó
Nếu khong có ký tự xác định loại:
Số có dấu chấm hoặc viết theo kiểu khoa học (có E): số thực
Số khác: số nguyên
Số nguyên trong vòng giới hạn của Integer là integer, ngoài giới hạn của Integer thì là Long (máy của tôi khi gặp số lớn hơn Long thì nó tự động gài thêm ký tự # để thành Double)

Trong code trên, 50 và 1000 đều nhỏ hơn 32767 cho nên cả hai mặc định là Integer
Trong biểu thức tính kia 50 * 1000 là con toán nhân 2 số integers cho nên mặc định kết quả là integer; và bị tràn số (50000 > 32767).

Muốn sửa thì chỉ cần chỉnh 1 trong 2 số (50 và 1000) thành kiểu lớn hơn. Kết quả của tích 2 số tự động là kiểu lớn hơn (*)
Cách 1: thêm & để thành Long
Cách 2: thêm 1 dấu chấm phía sau để thành Double (máy của toi tự động đổi dấu chấm phía sau thành #)
Trong trường hợp này, cách 2 tốt hơn

Cái này cho bài #1:
PHP:
Function tiendien(ByVal sodien As Double) As Double
    If sodien <= 50 Then
        tiendien = sodien * 1000
    Else
        tiendien = 50 * CDbl(1000) + CDbl(sodien - 50) * 2000
    End If
End Function
Chỉ cần sửa 50 * 1000 bởi 50.0 * 1000 là đã chạy được rồi.

Máy tính làm con toán nhân số thực khác với nhân số nguyên. Vì vậy, các ngôn ngữ đều có luật ép kiểu.
Khi 2 số nhân/chia nhau thì số có kiểu nhỏ hơn sẽ được ép qua kiểu lớn và kết quả là kiểu lớn.

Trong biểu thức trên, (sodien - 50) * 2000 có sodien là double ròi cho nên khong cần phải ép kiểu nữa. Chỉ 50 * 1000 thì cần phải ép kiểu.
Theo nguyên tắc, 1000# là hằng, CDbl(1000) là hàm được nạp tham số hằng. Hằng luôn luôn hiệu quả hơn.
 
Lần chỉnh sửa cuối:
Upvote 0
Vậy tức là số 50 không phải là số thực?
Còn số 50.0 mới là số thực?


Mình không dám tin vậy đâu, nhất là bài của các anh ních màu xanh lá.
Bác lại bắt bẻ quá rồi. Nói số thực ở đây là đang nói với anh VBA, nghĩa là nói đến kiểu dữ liệu, chứ ai chẳng biết rằng mỗi số nguyên đều là số thực.
Ngoài ra, việc trả lời bài viết thì liên quan gì đến xanh lá hay xanh dương nhỉ?
 
Upvote 0
Nó không hề đoán. Luật số literals được nó định là:
Số có ký tự chỉ rõ loại: theo loại đó
Nếu khong có ký tự xác định loại:
Số có dấu chấm hoặc viết theo kiểu khoa học (có E): số thực
Số khác: số nguyên
Số nguyên trong vòng giới hạn của Integer là integer, ngoài giới hạn của Integer thì là Long (máy của tôi khi gặp số lớn hơn Long thì nó tự động gài thêm ký tự # để thành Double)

Trong code trên, 50 và 1000 đều nhỏ hơn 32767 cho nên cả hai mặc định là Integer
Trong biểu thức tính kia 50 * 1000 là con toán nhân 2 số integers cho nên mặc định kết quả là integer; và bị tràn số (50000 > 32767).

Muốn sửa thì chỉ cần chỉnh 1 trong 2 số (50 và 1000) thành kiểu lớn hơn. Kết quả của tích 2 số tự động là kiểu lớn hơn (*)
Cách 1: thêm & để thành Long
Cách 2: thêm 1 dấu chấm phía sau để thành Double (máy của toi tự động đổi dấu chấm phía sau thành #)
Trong trường hợp này, cách 2 tốt hơn
Bác ơi VB interger là 4 bytes, ở đây là kiểu short int 2 bytes.
 
Upvote 0
Về nguyên nhân thì tôi đã viết ở 2 bài dưới (năm 2013, 2014). Bài 2 tôi nói cả về cách khắc phục.
Tôi không dùng &, # vì chúng chả gợi ý gì cả. Phải nhớ, phải học thuộc lòng. Thế thôi. Còn CByte, CInt, CLng, CDbl thì chỉ nhìn code là hiểu.

https://www.giaiphapexcel.com/diendan/threads/các-câu-hỏi-về-mảng-trong-vba-array.46834/post-548363

https://www.giaiphapexcel.com/diend...g-việc-tính-toán-số-quá-lớn.90497/post-565069
 
Upvote 0
Web KT
Back
Top Bottom