ฉันกำลังคิดถึงวิธีแสดงการควบคุมเลขหน้าโดยเฉพาะเมื่อใช้ภาษาเช่น C # หรือ Java
หากฉันมีรายการxที่ฉันต้องการแสดงในหน่วยของyต่อหน้าจะต้องมีกี่หน้า?
x
หารด้วยy
, y/x + 1
จะเป็นหนึ่งในที่สูงเกินไป
ฉันกำลังคิดถึงวิธีแสดงการควบคุมเลขหน้าโดยเฉพาะเมื่อใช้ภาษาเช่น C # หรือ Java
หากฉันมีรายการxที่ฉันต้องการแสดงในหน่วยของyต่อหน้าจะต้องมีกี่หน้า?
x
หารด้วยy
, y/x + 1
จะเป็นหนึ่งในที่สูงเกินไป
คำตอบ:
พบทางออกที่สง่างาม:
int pageCount = (records + recordsPerPage - 1) / recordsPerPage;
pageCount = -((-records) // recordsPerPage)
คือ
การแปลงเป็นจุดลอยตัวและด้านหลังดูเหมือนว่าเป็นการเสียเวลาอย่างมากที่ระดับ CPU
ทางออกของ Ian Nelson:
int pageCount = (records + recordsPerPage - 1) / recordsPerPage;
สามารถทำให้ง่ายขึ้นไปที่:
int pageCount = (records - 1) / recordsPerPage + 1;
AFAICS นี่ไม่มีข้อผิดพลาดล้นที่แบรนดอนดูเรตต์ชี้ให้เห็นและเนื่องจากมันใช้เพียงครั้งเดียวคุณไม่จำเป็นต้องจัดเก็บ recordsPerPage เป็นพิเศษหากมันมาจากฟังก์ชั่นราคาแพงเพื่อดึงค่าจากไฟล์ config หรือ บางสิ่งบางอย่าง
เช่นนี้อาจไม่มีประสิทธิภาพหาก config.fetch_value ใช้การค้นหาฐานข้อมูลหรือบางสิ่ง:
int pageCount = (records + config.fetch_value('records per page') - 1) / config.fetch_value('records per page');
สิ่งนี้สร้างตัวแปรที่คุณไม่ต้องการซึ่งอาจมีหน่วยความจำ (รอง) และพิมพ์เพียงมากเกินไป:
int recordsPerPage = config.fetch_value('records per page')
int pageCount = (records + recordsPerPage - 1) / recordsPerPage;
นี่คือทั้งหมดหนึ่งบรรทัดและดึงข้อมูลเพียงครั้งเดียว:
int pageCount = (records - 1) / config.fetch_value('records per page') + 1;
-1 / 1 + 1 = 0
บันทึก: ในขณะที่ไม่ใช่เหตุการณ์ที่เกิดขึ้นทั่วไปเป็นสิ่งสำคัญที่ต้องจำไว้ว่าถ้าคุณอนุญาตให้ผู้ใช้ปรับขนาดหน้า ดังนั้นไม่อนุญาตให้ผู้ใช้มีขนาดหน้า 1 ตรวจสอบขนาดหน้าหรือทั้งสองอย่าง (อาจดีกว่าเพื่อหลีกเลี่ยงพฤติกรรมที่ไม่คาดคิด)
สำหรับ C # การแก้ปัญหาคือการแปลงค่าให้เป็นสองเท่า (เนื่องจาก Math.Ceiling ใช้ค่าเป็นสองเท่า):
int nPages = (int)Math.Ceiling((double)nItems / (double)nItemsPerPage);
ใน java คุณควรทำสิ่งเดียวกันกับ Math.ceil ()
int
เพราะMath.Ceiling
ส่งกลับค่าdouble
หรือdecimal
ขึ้นอยู่กับประเภทอินพุต
สิ่งนี้จะให้สิ่งที่คุณต้องการ คุณจะต้องการให้ x รายการหารด้วย y รายการต่อหน้าปัญหาคือเมื่อตัวเลขไม่สม่ำเสมอดังนั้นหากมีบางส่วนเราต้องการเพิ่มอีกหนึ่งหน้า
int x = number_of_items;
int y = items_per_page;
// with out library
int pages = x/y + (x % y > 0 ? 1 : 0)
// with library
int pages = (int)Math.Ceiling((double)x / (double)y);
วิธีแก้ปัญหาคณิตศาสตร์จำนวนเต็มที่ Ian จัดไว้นั้นดี แต่ก็มีปัญหาจากข้อผิดพลาดที่ล้นจำนวนเต็ม สมมติว่าตัวแปรทั้งหมดint
เป็นโซลูชันสามารถเขียนใหม่เพื่อใช้long
คณิตศาสตร์และหลีกเลี่ยงข้อผิดพลาด:
int pageCount = (-1L + records + recordsPerPage) / recordsPerPage;
หากrecords
เป็น a long
ข้อผิดพลาดจะยังคงอยู่ โซลูชันโมดูลัสไม่มีข้อผิดพลาด
ตัวแปรของคำตอบของNick Berardiที่หลีกเลี่ยงสาขา:
int q = records / recordsPerPage, r = records % recordsPerPage;
int pageCount = q - (-r >> (Integer.SIZE - 1));
หมายเหตุ: (-r >> (Integer.SIZE - 1))
ประกอบด้วยเครื่องหมายบิตของr
ทำซ้ำ 32 ครั้ง (ขอบคุณเครื่องหมายส่วนขยายของ>>
โอเปอเรเตอร์) ค่านี้ประเมินเป็น 0 หากr
เป็นศูนย์หรือลบ -1 ถ้าr
เป็นค่าบวก ดังนั้นการลบได้จากq
มีผลกระทบของการเพิ่ม 1 records % recordsPerPage > 0
ถ้า
สำหรับบันทึก == 0 โซลูชันของ rjmunro ให้ 1 วิธีแก้ปัญหาที่ถูกต้องคือ 0 นั่นบอกว่าถ้าคุณรู้ว่าบันทึก> 0 (และฉันแน่ใจว่าเราทุกคนสันนิษฐาน recordPerPage> 0) แล้วโซลูชัน rjmunro ให้ผลลัพธ์ที่ถูกต้องและ ไม่มีปัญหาการล้นใด ๆ
int pageCount = 0;
if (records > 0)
{
pageCount = (((records - 1) / recordsPerPage) + 1);
}
// no else required
ทั้งหมดการแก้ปัญหาทางคณิตศาสตร์จำนวนเต็มจะมีประสิทธิภาพมากขึ้นกว่าที่ใด ๆของการแก้จุดลอย
ต้องการวิธีการขยาย:
public static int DivideUp(this int dividend, int divisor)
{
return (dividend + (divisor - 1)) / divisor;
}
ไม่มีการตรวจสอบที่นี่ (ล้น, DivideByZero
ฯลฯ ) อย่าลังเลที่จะเพิ่มถ้าคุณต้องการ โดยวิธีการสำหรับผู้ที่กังวลเกี่ยวกับค่าใช้จ่ายในการภาวนาวิธีการฟังก์ชั่นที่เรียบง่ายเช่นนี้อาจจะมีการคอมไพเลอร์อย่างไรก็ตามฉันไม่คิดว่ามันเป็นที่ที่ต้องกังวล ไชโย
ป.ล. คุณอาจพบว่ามีประโยชน์ที่จะต้องตระหนักถึงสิ่งนี้เช่นกัน (ได้รับส่วนที่เหลือ):
int remainder;
int result = Math.DivRem(dividend, divisor, out remainder);
DivideUp(4, -2)
ส่งคืน 0 (ควรเป็น -2) มันถูกต้องเฉพาะสำหรับจำนวนเต็มไม่เป็นลบซึ่งไม่ชัดเจนจากคำตอบหรือจากส่วนต่อประสานของฟังก์ชัน
อีกทางเลือกหนึ่งคือการใช้ฟังก์ชั่น mod () (หรือ '%') หากไม่มีส่วนที่เหลือเป็นศูนย์ให้เพิ่มผลลัพธ์จำนวนเต็มของการหาร
ฉันทำสิ่งต่อไปนี้จัดการกับโอเวอร์โฟลว์ใด ๆ :
var totalPages = totalResults.IsDivisble(recordsperpage) ? totalResults/(recordsperpage) : totalResults/(recordsperpage) + 1;
และใช้ส่วนขยายนี้หากมีผลลัพธ์ 0 รายการ:
public static bool IsDivisble(this int x, int n)
{
return (x%n) == 0;
}
นอกจากนี้สำหรับหมายเลขหน้าปัจจุบัน (ไม่ได้ถาม แต่อาจมีประโยชน์):
var currentPage = (int) Math.Ceiling(recordsperpage/(double) recordsperpage) + 1;
ทางเลือกในการลบการแยกย่อยในการทดสอบสำหรับศูนย์:
int pageCount = (records + recordsPerPage - 1) / recordsPerPage * (records != 0);
ไม่แน่ใจว่าสิ่งนี้จะใช้ได้ใน C # หรือไม่ควรทำใน C / C ++
วิธีการทั่วไปซึ่งผลลัพธ์ที่คุณสามารถทำซ้ำอาจเป็นที่สนใจ:
public static Object[][] chunk(Object[] src, int chunkSize) {
int overflow = src.length%chunkSize;
int numChunks = (src.length/chunkSize) + (overflow>0?1:0);
Object[][] dest = new Object[numChunks][];
for (int i=0; i<numChunks; i++) {
dest[i] = new Object[ (i<numChunks-1 || overflow==0) ? chunkSize : overflow ];
System.arraycopy(src, i*chunkSize, dest[i], 0, dest[i].length);
}
return dest;
}
Lists.partition(List, int)
) และแดกดันsize()
วิธีการที่เกิดขึ้นList
( ณr09
) ทนทุกข์ทรมานจากข้อผิดพลาดล้นที่ระบุไว้ในคำตอบของแบรนดอน DuRette ของ
ฉันมีความต้องการที่คล้ายกันซึ่งฉันต้องการแปลงนาทีเป็นชั่วโมง & นาที สิ่งที่ฉันใช้คือ:
int hrs = 0; int mins = 0;
float tm = totalmins;
if ( tm > 60 ) ( hrs = (int) (tm / 60);
mins = (int) (tm - (hrs * 60));
System.out.println("Total time in Hours & Minutes = " + hrs + ":" + mins);
ต่อไปนี้ควรทำการปัดเศษที่ดีกว่าโซลูชันด้านบน แต่ต้องเสียค่าใช้จ่ายของประสิทธิภาพ (เนื่องจากการคำนวณจุดลอยตัวของ 0.5 * rctDenominator):
uint64_t integerDivide( const uint64_t& rctNumerator, const uint64_t& rctDenominator )
{
// Ensure .5 upwards is rounded up (otherwise integer division just truncates - ie gives no remainder)
return (rctDenominator == 0) ? 0 : (rctNumerator + (int)(0.5*rctDenominator)) / rctDenominator;
}
คุณจะต้องทำการหารจำนวนจุดลอยตัวจากนั้นใช้ฟังก์ชันเพดานเพื่อปัดเศษค่าเป็นจำนวนเต็มถัดไป