Làm tròn lên, làm tròn xuống theo block number

  • Thread starter Thread starter hai2hai
  • Ngày gửi Ngày gửi
Liên hệ QC

hai2hai

VNUNi®
Thành viên danh dự
Tham gia
14/6/06
Bài viết
1,137
Được thích
2,297
Nghề nghiệp
Tư vấn giải pháp bán lẻ
Mình có 1 bài nho nhỏ gửi tới mọi người:

Bài toán liên quan tới việc chấm công tự động bằng thẻ về việc đi muộn, về sớm đối với nhân viên trong công ty

Mục tiêu:
- Lựa chọn làm tròn lên theo Block: Giả sử nhân viên đi muộn là từ 1 đến 10 phút thì sẽ làm tròn lên thành 10 phút. Nếu đi muộn 11 đến 20 phút thì làm tròn là 20, v.v... Khi đó gọi số 10 là Block Number. (Cách này ko có lợi cho nhân viên)
- Lựa chọn làm tròn xuống theo Block: Giả sử nhân viên đi muộn là từ 1 đến 9 phút thì sẽ làm tròn xuống thành 0 phút. Nếu đi muộn 10 đến 19 phút thì làm tròn là 10 phút, v.v... Khi đó gọi số 10 là Block Number. Và trường hợp này gọi là làm tròn xuống (Cách này có lợi cho nhân viên)

Câu hỏi:
1. Hãy viết code để đáp ứng được việc trên
Ví dụ:
Private Function RoundUpByBlock(ByVal lngNumber&, ByVal lngBlockNumber&) As Long
Private Function RoundDownByBlock(ByVal lngNumber&, ByVal lngBlockNumber&) As Long

2. Tối ưu hóa những gì bạn viết, tốt nhất là chỉ cần 1 dòng thôi


Cheers,
 
Ở đây mình vẫn chưa hiểu 1 chổ:
Theo như những gì mô tả ở trên thì bài toán này là tìm số block dựa vào thời gian đi trể ---> Vậy chỉ có 1 biến thôi chứ
 
Upvote 0
Đúng là chỉ cần 1 dòng:

[highlight=vb]Private Function RoundUpByBlock(ByVal lngNumber&, ByVal lngBlockNumber&) As Long
RoundUpByBlock = Int(lngNumber&, lngBlockNumber&) * lngBlockNumber& + lngBlockNumber&
End Function[/highlight]

[highlight=vb]Private Function RoundDownByBlock(ByVal lngNumber&, ByVal lngBlockNumber&) As Long
RoundDownByBlock = Int(lngNumber&, lngBlockNumber&) * lngBlockNumber&
End Function[/highlight]
 
Lần chỉnh sửa cuối:
Upvote 0
RoundUp and RoundDown

Mình có 1 bài nho nhỏ gửi tới mọi người:

Bài toán liên quan tới việc chấm công tự động bằng thẻ về việc đi muộn, về sớm đối với nhân viên trong công ty

Mục tiêu:
- Lựa chọn làm tròn lên theo Block: Giả sử nhân viên đi muộn là từ 1 đến 10 phút thì sẽ làm tròn lên thành 10 phút. Nếu đi muộn 11 đến 20 phút thì làm tròn là 20, v.v... Khi đó gọi số 10 là Block Number. (Cách này ko có lợi cho nhân viên)
- Lựa chọn làm tròn xuống theo Block: Giả sử nhân viên đi muộn là từ 1 đến 9 phút thì sẽ làm tròn xuống thành 0 phút. Nếu đi muộn 10 đến 19 phút thì làm tròn là 10 phút, v.v... Khi đó gọi số 10 là Block Number. Và trường hợp này gọi là làm tròn xuống (Cách này có lợi cho nhân viên)

Câu hỏi:
1. Hãy viết code để đáp ứng được việc trên
Ví dụ:
Private Function RoundUpByBlock(ByVal lngNumber&, ByVal lngBlockNumber&) As Long
Private Function RoundDownByBlock(ByVal lngNumber&, ByVal lngBlockNumber&) As Long

2. Tối ưu hóa những gì bạn viết, tốt nhất là chỉ cần 1 dòng thôi


Cheers,


Tôi nghĩ chỉ cần dùng 2 hàm:
Ceiling(lngNumber&, lngBlockNumber) và Floor(lngNumber&, lngBlockNumber)
 
Upvote 0
Nếu coding trong môi trường khác không phải là Excel thì có lẽ cần. Nếu trong môi trường excel, ta có hai hàm Ceiling Floor để giải quyết rồi (như hoangvuluan đã nói), không cần viết code chi nữa!
 
Upvote 0
Mr Hải mà hỏi, 99% là hỏi trong môi trường khác, không phải hỏi excel
 
Upvote 0
Đúng là chỉ cần 1 dòng:

[highlight=vb]Private Function RoundDownByBlock(ByVal lngNumber&, ByVal lngBlockNumber&) As Long
RoundDownByBlock = Int(lngNumber&, lngBlockNumber&) * lngBlockNumber&
End Function[/highlight]
Int(lngNumber&, lngBlockNumber&) cú pháp này hình như sai.
Có thể dồn 2 vào 1 luôn, nhưng tôi chưa biết làm thế nào nAlt thông số nào phải = 1 hoặc 0
PHP:
Private Function RoundByBlock(ByVal lngNumber&, ByVal lngBlockNumber&, Optional nAlt As Byte) As Long
RoundByBlock = Int(lngNumber& / lngBlockNumber&) * lngBlockNumber& + lngBlockNumber& * IIf(nAlt = 0, 0, 1)
End Function
 
Upvote 0
Đúng là chỉ cần 1 dòng:

[highlight=vb]Private Function RoundUpByBlock(ByVal lngNumber&, ByVal lngBlockNumber&) As Long
RoundUpByBlock = Int(lngNumber&, lngBlockNumber&) * lngBlockNumber& + lngBlockNumber&
End Function[/highlight]

[highlight=vb]Private Function RoundDownByBlock(ByVal lngNumber&, ByVal lngBlockNumber&) As Long
RoundDownByBlock = Int(lngNumber&, lngBlockNumber&) * lngBlockNumber&
End Function[/highlight]

Hàm Int chỉ có một đối số thôi bác. Không rõ bác ptm0412 test ở môi trường nào thế? Nhưng hướng của bác là đúng rồi.

Mr Hải mà hỏi, 99% là hỏi trong môi trường khác, không phải hỏi excel
Đúng là h2h chỉ hỏi trong VB chứ ko để ý Excel có Floor với Ceiling (mục tiêu là giống Floor và Ceiling)

Đáp án cực kỳ đơn giản, đúng là chỉ 1 dòng, chỉ có RoundUp thì dùng tới Int(), còn RoundDown thì ko cần tới bất cứ hàm nào (và cũng chỉ có 1 dòng)
 
Lần chỉnh sửa cuối:
Upvote 0
Nhầm, nhầm chết người thật. Đúng ra là Int(lngNumber&/ lngBlockNumber&)

Vậy:
1. RoundUpByBlock = Int(lngNumber&/ lngBlockNumber&) * lngBlockNumber& + lngBlockNumber&

2. RoundDownByBlock = Int(lngNumber&/ lngBlockNumber&) * lngBlockNumber&
còn RoundDown thì ko cần tới bất cứ hàm nào (và cũng chỉ có 1 dòng)
RoundDown mà không cần Int thì làm sao vậy Mr. Hải?
 
Lần chỉnh sửa cuối:
Upvote 0
Vậy:
1. RoundUpByBlock = Int(lngNumber&/ lngBlockNumber&) * lngBlockNumber& + lngBlockNumber&

Anh đã thử cho lngNumber = 5, lngBlockNumber = 5 chưa?

Tại sao em đi làm muộn 5 phút (và trong khi Block = 5) mà anh lại cho là em đi làm muộn 10 phút vậy? Làm thế là em ... kiện anh đấy.

Anh thử nhé:
RoundUp: int((number+ block)/block) * block

RoundDown mà không cần Int thì làm sao vậy Mr. Hải?

Anh thử cái này xem sao:

RoundDown: (number \ block) * block
 
Lần chỉnh sửa cuối:
Upvote 0
Cái dấu "\" hình như đã gặp trong bài của bác SA_DQ rồi thì phải, bài về lập hàm trả về số quý của ngày hiện hành. "\" là phép chia lấy phần nguyên phải không anh hai2hai ?
 
Upvote 0
Hà, number \ Block thì cũng là Int(Number/ Block)

Còn cái vụ
Anh đã thử cho lngNumber = 5, lngBlockNumber = 5 chưa?
Mã:
RoundUp: int((number+ block)/block) * block
cũng bị như thường!
đây nhé:
RoundUp = Int((5 + 5)/5) * 5 = 10 !!!!!

RoundDown cũng bị tình trạng đó.

Vầy chắc đúng hơn:

RoundUp = Int(number / (block + 0.01)) * block + block

RoundDown = Number \ (Block + 0.01)
 
Lần chỉnh sửa cuối:
Upvote 0
Còn cái vụ
Mã:
RoundUp: int((number+ block)/block) * block
cũng bị như thường!
đây nhé:
RoundUp = Int((5 + 5)/5) * 5 = 10 !!!!!

RoundDown cũng bị tình trạng đó.

Vầy chắc đúng hơn:

RoundUp = Int(number / (block + 0.01)) * block + block

RoundDown = Number \ (Block + 0.01)

Vụ RoundDown:
?(5\5)* 5 = 5 (đi muộn 5 phút thì làm tròn theo Block là 5 là chuẩn rồi anh ơi)

Vụ RoundUp đúng là em cũng ko test trường hợp mà khi em test cái của anh. :)

RoundUp = Int(number / (block + 0.01)) * block + block

Em ko đi muộn phút nào anh lại cho em đi muộn ... 5 phút

Int(0/ (5+ 0.01)) * 5+ 5 = 5 ???

Cái hàm dài dài thì nó như thế này:

Private Function RoundUpByBlock(ByVal lngNumber As Long, ByVal lngBlock As Long) As Long
If Int(lngNumber Mod lngBlock) = 0 Then
RoundUpByBlock = (lngNumber / lngBlock) * lngBlock
Else
RoundUpByBlock = Int((lngNumber / lngBlock) + 1) * lngBlock
End If
End Function

Or Shorter is:

Int((lngNumber / lngBlock) + IIf(Int(lngNumber Mod lngBlock) = 0, 0, 1)) * lngBlock

Test cases:

Debug.Print RoundUpByBlock(0, 5) = 0
Debug.Print RoundUpByBlock(1, 5) = 5
Debug.Print RoundUpByBlock(5, 5) = 5
Debug.Print RoundUpByBlock(6, 5)= 10

Vấn đề là phải thay cái hàm RoundUpByBlock dài dài ở trên thành 1 dòng ngắn như là đã làm với RoundDown (RoundDown = (n\b) * b là chuẩn rồi)
 
Lần chỉnh sửa cuối:
Upvote 0
Đáp án cực kỳ đơn giản, đúng là chỉ 1 dòng, chỉ có RoundUp thì dùng tới Int(), còn RoundDown thì ko cần tới bất cứ hàm nào (và cũng chỉ có 1 dòng)
Tôi nghĩ mấu chốt vấn đề nằm ở chổ ta khai báo
RoundDownByBlock(ByVal lngNumber&, ByVal lngBlockNumber&) As Long
Nên khỏi cần làm tròn
 
Upvote 0
Tôi nghĩ mấu chốt vấn đề nằm ở chổ ta khai báo
RoundDownByBlock(ByVal lngNumber&, ByVal lngBlockNumber&) As Long
Nên khỏi cần làm tròn

Không phải vấn đề đó. Dĩ nhiên kiểu trở về là kiểu Long rồi. Mấy hàm đó viết ra cho dễ hiểu thôi, giờ mọi người hiểu đầu bài rồi thì ko care tới tên hàm đó nữa.
 
Upvote 0
Tạm thời, đây là giải pháp cho ra kết quả đúng:

RoundUpByBlock = Int((lngNumber / lngBlock) + IIf(lngNumber Mod lngBlock = 0, 0, 1)) * lngBlock
Hoặc:
RoundUpByBlock = ((lngNumber \ lngBlock) + IIf(lngNumber Mod lngBlock = 0, 0, 1)) * lngBlock

Kết quả:
RoundUpByBlock(0, 5) = 0
RoundUpByBlock(1, 5) = 5
RoundUpByBlock(5, 5) = 5
RoundUpByBlock(6, 5) = 10
RoundUpByBlock(10, 5) = 10
RoundUpByBlock(13, 5) = 15
RoundUpByBlock(15, 5) = 15
RoundUpByBlock(17, 5) = 20

RoundDownByBlock = (lngNumber \ lngBlock ) * lngBlock

Kết quả:
RoundDownByBlock(0, 5) = 0
RoundDownByBlock(4, 5) = 0
RoundDownByBlock(5, 5) = 5
RoundDownByBlock(9, 5) = 5
RoundDownByBlock(10, 5) = 10
RoundDownByBlock(13, 5) = 10
RoundDownByBlock(15, 5) = 15
RoundDownByBlock(19, 5) = 15

Chú ý:
- RoundUp & RoundDown sẽ có cùng kết quả khi lngBlock = 1 (áp dụng trường hợp tính đi muộn, về sớm theo kết quả thực tế chứ ko làm tròn)


Ai có ý tưởng gì mới "đẹp" hơn ko?
 
Lần chỉnh sửa cuối:
Upvote 0
Tạm thời, đây là giải pháp cho ra kết quả đúng:

RoundUpByBlock = Int((lngNumber / lngBlock) + IIf(lngNumber Mod lngBlock = 0, 0, 1)) * lngBlock
Hoặc:
RoundUpByBlock = ((lngNumber \ lngBlock) + IIf(lngNumber Mod lngBlock = 0, 0, 1)) * lngBlock

Kết quả:


RoundDownByBlock = (lngNumber \ lngBlock ) * lngBlock

Kết quả:


Chú ý:
- RoundUp & RoundDown sẽ có cùng kết quả khi lngBlock = 1 (áp dụng trường hợp tính đi muộn, về sớm theo kết quả thực tế chứ ko làm tròn)


Ai có ý tưởng gì mới "đẹp" hơn ko?


Cũng chỉ viết lại cho gọn thôi:
RoundUpByBlock = ((lngNumber \ lngBlock) - (lngNumber Mod lngBlock <> 0)) * lngBlock
(Trong VBA, True = -1, khác với trong E: True=1)
 
Upvote 0
RoundUpByBlock = Int((lngNumber / lngBlock) + IIf(lngNumber Mod lngBlock = 0, 0, 1)) * lngBlock
Hoặc:
RoundUpByBlock = ((lngNumber \ lngBlock) + IIf(lngNumber Mod lngBlock = 0, 0, 1)) * lngBlock
Kết chỉ có hai điều kiện thì có thể không cần IIF không?
[highlight=vb]RoundUpByBlock = lngBlock * ((lngNumber \ lngBlock) - ((lngNumber Mod lngBlock) > 0))[/highlight]
 
Upvote 0
Đúng. Có vẻ ngắn hơn 1 chút dựa vào True = -1
 
Lần chỉnh sửa cuối:
Upvote 0
Web KT

Bài viết mới nhất

Back
Top Bottom