https://tavianator.com/2024/percent.html [ ] 1. Home 2. Projects 3. 1. bfs 2. acap 3. bistring 4. 2024 5. 1. Rounding percentages 2. Bug hunting in Btrfs 6. 2023 7. 1. Translucent typedefs in C 2. bfs 3.0: the fastest find yet! 3. You could have invented futexes 4. Irregular expressions 8. 2022 9. 1. Fast, Branchless Ray/Bounding Box Intersections, Part 3: Boundaries 2. Remote reboots with encrypted disks 3. Parallelizing graph search with Rayon 4. Long division 10. 2020 11. 1. Proving that 1 + 1 = 10 in Rust 2. OOMify 3. Makeover 4. Porting k-d forests to Rust 12. 2018 13. 1. spawn() of Satan 2. Cracking DHCE (Diffie-Hellman color exchange) 14. 2017 15. 1. bfs from the ground up, part 3: optimization 2. bfs from the ground up, part 2: parsing 16. 2016 17. 1. A quick trick for faster naive matrix multiplication 2. bfs from the ground up, part 1: traversal 3. The Approximating and Eliminating Search Algorithm 18. 2015 19. 1. Java autoboxing performance 2. Fast, Branchless Ray/Bounding Box Intersections, Part 2: NaNs 20. 2014 21. 1. Efficient Integer Exponentiation in C 2. Standards-compliant* alloca() 3. The Visitor Pattern in Python 4. Exact Bounding Boxes for Spheres/Ellipsoids 5. A Beautiful Ray/Mesh Intersection Algorithm 6. A Beautiful Ray/Triangle Intersection Method 7. Announcing Sangria 8. k-d Forests 9. Big Numbers 22. 2013 23. 1. Java Generics Quirks 2. Fair and Square, or How to Count to a Googol 24. 2012 25. 1. Iterating Over Binary Trees 26. 2011 27. 1. Collisions 2. Ray / Priority R-Tree Intersection 3. Priority R-Trees 4. Fast, Branchless Ray/Bounding Box Intersections 5. Fast Binary-Coded Decimal Addition and Subtraction 6. Facebook Hacker Cup Qualification Round: Double Squares 28. 2010 29. 1. Righteous hack: getting 263 - 1 points in a silly Facebook game 2. Solving Cubic Polynomials 3. Solving Polynomials 4. .com * Light * Rust * Coal * Navy * Ayu tavianator.com [ ] Rounding percentages 2024-06-21 Tavian Barnes Let's say you're downloading a file and you see this: 0% How do you know the download actually started? Similarly, if you see this: 100% Is it actually done? Or did it download 999/1000 bytes and then hang? I know this is a relatively minor thing, but I find myself frustrated by UIs like this so often that I'm proposing these rules for rounding percentages that are shown to users: * 0% means exactly zero percent. If the user sees 0%, they can assume that absolutely nothing has happened yet except rendering the progress bar. * 100% means finished. If the user sees 100%, the process is finished, done, over, complete. They shouldn't have to wait for anything else to happen to start using the thing. Don't show 100% and then call fsync() or something silly. In between those values, interpolate as normal. There are a few ways to implement this. With (truncating) integer division, you just have to fix up the 0% case: >>> def percent(progress, total): ... ret = 100 * progress // total ... if ret == 0 and progress > 0: ... return 1 ... else: ... return ret ... >>> percent(0, 1000) 0 >>> percent(1, 1000) 1 >>> percent(999, 1000) 99 >>> percent(1000, 1000) 100 There's also a neat trick with floating point: the default rounding mode is typically ties-to-even. So if we interpolate between [0.5,99.5][0.5, 99.5][0.5,99.5] instead of [0,100][0, 100][0,100], the endpoints will round correctly and everything else will stay within [1,99][1, 99][1,99]: >>> def percent(progress, total): ... return round(99 * progress / total + 0.5) ... >>> percent(0, 1000) 0 >>> percent(1, 1000) 1 >>> percent(999, 1000) 99 >>> percent(1000, 1000) 100 (If your language has bad defaults, you may have to ask for the right rounding mode explicitly.)