rinohtype icon indicating copy to clipboard operation
rinohtype copied to clipboard

floating poind rounding error leads to assertion failure

Open hartmans opened this issue 4 years ago • 2 comments

On master commit ed1b2b2deb8b08 I get a crash with an assertion failure at line 1112 in paragraph.py, the assertion failes calling container.advance2(descender) The problem is that the container has just enough height left, but there's a floating point rounding error:

(Pdb) p float(container.remaining_height) + descender
-5.329070518200751e-15

I'd prefer not to share the source files, although we could talk about doing so privately if it's really necessary. However, whenever there's a chance of a floating point comparison needing exact equality, you need to account for rounding error like the above. I think the appropriate fix would either be in advance2 or in the equality operators of the dimension objects depending on how global of a fix you want.

hartmans avatar Oct 30 '21 15:10 hartmans

diff --git a/src/rinoh/layout.py b/src/rinoh/layout.py
index 48b7745b..ff6160a8 100644
--- a/src/rinoh/layout.py
+++ b/src/rinoh/layout.py
@@ -271,7 +271,7 @@ class FlowablesContainerBase(Container):
         bottom of the container.
 
         """
-        if height <= self.remaining_height:
+        if height <= self.remaining_height+1e-10:
             self._self_cursor.grow(height)
         elif ignore_overflow:
             self._self_cursor.grow(float(self.remaining_height))

is a quick fix for what I'm running into. I'm not going to go fill out a CLA and submit that as a pull request because it's too sloppy. I'd assume at a minimum you'd want to define some global fuzz constant (possibly even make it configurable) because it seems likely you'll run into this sort of issue in other places as well.

hartmans avatar Oct 30 '21 15:10 hartmans

Thanks for the bug report and analysis!

Floating point rounding errors are in fact something I wondered about before, but I haven't yet run into any issues because of them myself. A proper solution would be to use Python's Decimal type. These are reportedly 3 times slower than floats, but I doubt that would have much of an impact on the total rendering time. Alternatively, integers representing 1/100th of a Postscript point could be used.

I've committed your suggested quick fix, but I'll leave this issue open to track the bigger issue.

brechtm avatar Nov 04 '21 13:11 brechtm