Description: I have a Python function for round up numbers, that works fine: ' # RoundUP.py file in Script ' from decimal import Decimal, getcontext, ROUND_HALF_UP # # Round UP ' round_context = getcontext() ' round_context.rounding = ROUND_HALF_UP ' # ------------------------------------- ' def roundUp(x, digits, precision=5): ' tmp = round(Decimal(x), precision) ' fRet = float(tmp.__round__(digits)) ' return fRet ' # --------------------------------------------------------------- ' if __name__ == '__main__': ' fRU = roundUp(2.125, 2) # -> 2.13 ' fRU = roundUp(3.125, 2) # -> 3.13 ' fRU = roundUp(-2.125, 2) # -> -2.13 ' fRU = roundUp(4.125, 2) # -> 4.13 ' fRU = roundUp(2.225, 2) # -> 2.23 ' pass I call that function from Basic, and the result change: fRU = RoundUp(2.125, 2) ' 2.12 Now i have 2.12, not 2.13. Why ??? '---BASIC------------------------ Function RoundUp(num, dec) ' Number to Double Up Dim vRoundUp sFunctionPy = "vnd.sun.star.script:RoundUP.py$roundUp"& _ "?language=Python&location=user" oMSPF = createUnoService( _ "com.sun.star.script.provider.MasterScriptProviderFactory") gScriptProvider = oMSPF.createScriptProvider("") oScript = gScriptProvider.getScript(sFunctionPy) vRoundUp = oScript.invoke(Array(num, dec), Array(), Array()) RoundUp = vRoundUp End Function Steps to Reproduce: 1.Copy a RoundUP.py file in Script (the code is in Description above) 2.Run Main in Calc RounUP.ods 3.Examine the different results Actual Results: 2.12 Expected Results: 2.13 Reproducible: Always User Profile Reset: No Additional Info: Version: 7.1.8.1 (x64) / LibreOffice Community Build ID: e1f30c802c3269a1d052614453f260e49458c82c CPU threads: 16; OS: Windows 10.0 Build 22621; UI render: Skia/Raster; VCL: win Locale: it-IT (it_IT); UI: it-IT Calc: CL
Created attachment 184399 [details] macro
I copied it to instdir/share/RoundUP.py as: from decimal import Decimal, getcontext, ROUND_HALF_UP # # Round UP round_context = getcontext() round_context.rounding = ROUND_HALF_UP # ------------------------------------- def roundUp(x, digits, precision=5): tmp = round(Decimal(x), precision) fRet = float(tmp.__round__(digits)) return fRet # --------------------------------------------------------------- if __name__ == '__main__': fRU = roundUp(2.125, 2) # -> 2.13 fRU = roundUp(3.125, 2) # -> 3.13 fRU = roundUp(-2.125, 2) # -> -2.13 fRU = roundUp(4.125, 2) # -> 4.13 fRU = roundUp(2.225, 2) # -> 2.23 pass Accordingly, in the Basic script I changed the location to share: sFunctionPy = "vnd.sun.star.script:RoundUP.py$roundUp"& _ "?language=Python&location=share" When I run it, I get BASIC runtime error. Argument is not optional pointing to line vRoundUp = oScript.invoke(Array(num, dec), Array(), Array()) Please advise. Arch Linux 64-bit, X11 Version: 7.6.0.0.alpha0+ (X86_64) / LibreOffice Community Build ID: f0ff4243d45b11f372a2ed824fbb8806de9cb595 CPU threads: 8; OS: Linux 6.2; UI render: default; VCL: kf5 (cairo+xcb) Locale: fi-FI (fi_FI.UTF-8); UI: en-US Calc: threaded Built on 17 March 2023
Dear edil, This bug has been in NEEDINFO status with no change for at least 6 months. Please provide the requested information as soon as possible and mark the bug as UNCONFIRMED. Due to regular bug tracker maintenance, if the bug is still in NEEDINFO status with no change in 30 days the QA team will close the bug as INSUFFICIENTDATA due to lack of needed information. For more information about our NEEDINFO policy please read the wiki located here: https://wiki.documentfoundation.org/QA/Bugzilla/Fields/Status/NEEDINFO If you have already provided the requested information, please mark the bug as UNCONFIRMED so that the QA team knows that the bug is ready to be confirmed. Thank you for helping us make LibreOffice even better for everyone! Warm Regards, QA Team MassPing-NeedInfo-Ping
Dear Buovjaga, why don't you test in the same my environment (windows) and in the same location (user) ? "The statement BASIC runtime error. Argument is not optional pointing to line vRoundUp = oScript.invoke(Array(num, dec), Array(), Array()) " i think simplicity to try : oScript.invoke(Array(num, dec, 5), Array(), Array()) If you know a better code or advice to obtain the round up, please notice me. Thank you
Alain: any idea about this?
Edil, You're obviously tackling a complex topic here! The difference LIES in the way Python and Basic store FP numbers, as well as in the way libO Scripting Framework converts FP numbers from a language to another. One needs such information to fully diagnose your bug. I would strongly advise to use Calc cells content - for Python & Basic tests - to guarantee that input numbers share identical FP formats. As well as I would resort to Calc rounding functions for your very case. more in: https://en.wikipedia.org/wiki/Floating-point_arithmetic PS: Observe the steps to reproduce such anomaly aren't precise enough, please amend them instead of pointing fingers the person assisting you..
Thank you Buovjaga and Alain Romedenne for help me, I apologize if you think I wasn't polite. I thought LO cell.Value as Double and Python floating point number, both 8 bytes was from IEEE 754. My app use for big ranges and complex calculation Range.DataArray to get an Array(Array()) of values from Calc Sheet, call python function for process them as argument and round results, and return an array(array()) to set values in the same sheet range. This make my routine very fast. The problem is that python must round some numbers ad then multiply them to other number, so the round difference is important. Do you have any idea to solve this behavior, or work around ? Is this a bug o simplicity
Hi Edil, I suggest you use Calc rounding - Round, RoundDown, RoundUp - functions instead of user defined functions: https://help.libreoffice.org/latest/en-US/text/scalc/01/04060106.html?&DbPAR=CALC ScriptForge Session service ExecuteCalcFunction() method provides such programming facility.. https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_session.html?DbPAR=BASIC .. and is based on "com.sun.star.sheet.FunctionAccess" UNO service. Refer to https://help.libreoffice.org/latest/en-US/text/sbasic/shared/calc_functions.html?DbPAR=BASIC#bm_id291592361063458 if you still require to resort to BASIC. Hope that helps
Thank you Alain for your suggests. In my 30 thousand code rows app, the general function structure is Basic --> Array --> python --> Array --> Basic for improve the faster execution. For me it is not good idea for each array value in Python call an LO API service, maybe I will add a little number like : round(x + 10**-(digits+3), digits), or the classic Round = Int(x * 10 ^ digits + 0.5) / 10 ^ digits What do you think? And about the bug (or incompatibility), it is not correctable? By Nicola
(In reply to Buovjaga from comment #2) > When I run it, I get > > BASIC runtime error. > Argument is not optional > > pointing to line > > vRoundUp = oScript.invoke(Array(num, dec), Array(), Array()) Because you must run not the RoundUp function directly, but some other code, that calls the function and passes all the values, like Sub Main MsgBox RoundUp(2.125, 2) End Sub Additionally, the script must be in 'instdir/share/Scripts/python/RoundUP.py'. (In reply to edil from comment #4) > Dear Buovjaga, why don't you test in the same my environment (windows) and > in the same location (user) ? Because not everyone can have the same environment. Reproduction phase involves people trying to repro in different environments. === Changing the *Python* code of roundUp to end with something like return repr(x) (so that it simply returns a string representation of the *passed* argument) shows that the value *passed from Basic to Python* is indeed 2.125 (and that is no wonder, since Basic uses IEEE 754, in which, 2.125 is representable exactly). Further changing the code to end with return repr(fRet) shows that it's the *calculation in Python* that has the problem. It happens both in Windows, and in Ubuntu (so not specific to LibreOffice build of Python). And yes, executing this code in Python prompt produces expected '2.13' both in Windows, and in Ubuntu. Since I'm not an expert in Python, I can only tell that it needs debugging what Python environment details differ in this case. Setting to NEW.
https://stackoverflow.com/questions/33019698/how-to-properly-round-up-half-float-numbers In fact, it seems that *exactly the behavior of Python in LibreOffice* is correct. Its 'round' does the half-to-even rounding, as the documentation explicitly states [1]. And the StackOverflow article discusses the proper Pythonic way to round up. Why isn't it correct when trying in Python shell, is unclear, and outside of scope here. [1] https://docs.python.org/3.8/library/functions.html#round