Mercurial > octave
changeset 32929:8893636d43a5 bytecode-interpreter
maint: Merge default to bytecode-interpreter
author | Arun Giridhar <arungiridhar@gmail.com> |
---|---|
date | Sun, 04 Feb 2024 14:54:11 -0500 |
parents | 000cb78b35fc (current diff) de39818dca5e (diff) |
children | da8fda0b7dd8 |
files | |
diffstat | 7 files changed, 66 insertions(+), 42 deletions(-) [+] |
line wrap: on
line diff
--- a/etc/NEWS.10.md Sat Feb 03 15:35:52 2024 +0100 +++ b/etc/NEWS.10.md Sun Feb 04 14:54:11 2024 -0500 @@ -15,6 +15,8 @@ * `--no-init-site` : Don't read site-wide configuration files at startup. * `--no-init-all` : Don't read any configuration files at startup. +- `nchoosek` algorithm is now ~2x faster and provides greater precision. + ### Graphical User Interface ### Graphics backend
--- a/libgui/src/m-editor/file-editor-interface.h Sat Feb 03 15:35:52 2024 +0100 +++ b/libgui/src/m-editor/file-editor-interface.h Sun Feb 04 14:54:11 2024 -0500 @@ -71,7 +71,7 @@ virtual void empty_script (bool, bool) = 0; - virtual void restore_session () = 0; + virtual void restore_session (bool) = 0; virtual void enable_menu_shortcuts (bool enable) = 0;
--- a/libgui/src/m-editor/file-editor.cc Sat Feb 03 15:35:52 2024 +0100 +++ b/libgui/src/m-editor/file-editor.cc Sun Feb 04 14:54:11 2024 -0500 @@ -114,7 +114,7 @@ m_find_dialog = nullptr; - m_closed = false; + m_closed = true; m_no_focus = false; m_editor_ready = false; @@ -324,8 +324,12 @@ } void -file_editor::restore_session () +file_editor::restore_session (bool visible) { + + if (! visible) + return; + gui_settings settings; //restore previous session @@ -1580,7 +1584,7 @@ { m_closed = false; - restore_session (); + restore_session (visible); } empty_script (false, visible);
--- a/libgui/src/m-editor/file-editor.h Sat Feb 03 15:35:52 2024 +0100 +++ b/libgui/src/m-editor/file-editor.h Sun Feb 04 14:54:11 2024 -0500 @@ -124,7 +124,7 @@ void check_actions (); void empty_script (bool startup, bool visible); - void restore_session (); + void restore_session (bool visible = true); signals:
--- a/libgui/src/main-window.cc Sat Feb 03 15:35:52 2024 +0100 +++ b/libgui/src/main-window.cc Sun Feb 04 14:54:11 2024 -0500 @@ -1836,7 +1836,10 @@ // This can not be done when the editor is created because all functions // must be known for the lexer's auto completion information m_editor_window->empty_script (true, false); - m_editor_window->restore_session (); + bool ed_visible = + settings.value (dw_is_visible.settings_key ().arg (m_editor_window->objectName ()), + dw_is_visible.def ()).toBool (); + m_editor_window->restore_session (ed_visible); #endif }
--- a/scripts/linear-algebra/logm.m Sat Feb 03 15:35:52 2024 +0100 +++ b/scripts/linear-algebra/logm.m Sun Feb 04 14:54:11 2024 -0500 @@ -197,7 +197,7 @@ %! -1.9769, -1.0922, -0.5831]; %! if (__have_feature__ ("LLVM_LIBCXX")) %! ## The math libraries in libc++ seem to require larger tolerances -%! tol = 60*eps; +%! tol = 65*eps; %! else %! tol = 40*eps; %! endif
--- a/scripts/specfun/nchoosek.m Sat Feb 03 15:35:52 2024 +0100 +++ b/scripts/specfun/nchoosek.m Sun Feb 04 14:54:11 2024 -0500 @@ -112,48 +112,53 @@ n = numel (v); if (n == 1 && isnumeric (v)) - ## Improve precision over direct call to prod(). - ## Steps: 1) Make a list of integers for numerator and denominator, - ## 2) filter out common factors, 3) multiply what remains. - k = min (k, v-k); - - if (isinteger (v) || isinteger (k)) - numer = (v-k+1):v; - denom = (1:k); + ## Compute number of combinations rather than actual set combinations. + try + ## Use subtraction operation to validate combining integer data types + ## and for type propagation rules between integer and floating point. + k = min (k, v-k); + catch + error ("nchoosek: incompatible input types for N (%s), K (%s)", ... + class (v), class (k)); + end_try_catch + is_int = isinteger (k); + if (is_int) + imax = intmax (k); else - ## For a ~25% performance boost, multiply values pairwise so there - ## are fewer elements in do/until loop which is the slow part. - ## Since Odd*Even is guaranteed to be Even, also take out a factor - ## of 2 from numerator and denominator. - if (rem (k, 2)) # k is odd - numer = [((v-k+1:v-(k+1)/2) .* (v-1:-1:v-(k-1)/2)) / 2, v]; - denom = [((1:(k-1)/2) .* (k-1:-1:(k+1)/2)) / 2, k]; - else # k is even - numer = ((v-k+1:v-k/2) .* (v:-1:v-k/2+1)) / 2; - denom = ((1:k/2) .* (k:-1:k/2+1)) / 2; - endif + imax = flintmax (k); endif - - ## Remove common factors from numerator and denominator - do - for i = numel (denom):-1:1 - factors = gcd (denom(i), numer); - [f, j] = max (factors); - denom(i) /= f; - numer(j) /= f; - endfor - denom = denom(denom > 1); - numer = numer(numer > 1); - until (isempty (denom)) - - C = prod (numer, "native"); - if (isfloat (C) && C > flintmax (C)) + C = 1; + for i = 1:k + if (C * (v - k + i) >= imax) + ## Avoid overflow / precision loss by determining the smallest + ## possible factor of (C * (n-k+i)) and i via the gcd. + ## Note that by design in each iteration + ## 1) C will always increase (factor is always > 1). + ## 2) C will always be a whole number. + ## Therefore, using the gcd will always provide the best possible + ## solution until saturation / has the least precision loss. + g1 = gcd (C, i); + g2 = gcd (v - k + i, i/g1); + C /= g1; + C *= (v - k + i)/g2; + if (is_int && (C == imax)) + break; # Stop here; saturation reached. + endif + C /= i/(g1 * g2); + else + C *= (v - k + i); + C /= i; + endif + endfor + if (! is_int && C > imax) warning ("Octave:nchoosek:large-output-float", ... "nchoosek: possible loss of precision"); - elseif (isinteger (C) && C == intmax (C)) + elseif (is_int && C == imax) warning ("Octave:nchoosek:large-output-integer", ... "nchoosek: result may have saturated at intmax"); endif + + ## Compute actual set combinations elseif (k == 0) C = v(zeros (1, 0)); # Return 1x0 object for Matlab compatibility elseif (k == 1) @@ -283,6 +288,15 @@ %! assert (x, uint8 (252)); %! assert (class (x), "uint8"); +## Test combining rules for integers and floating point +%!test +%! x = nchoosek (uint8 (10), single (5)); +%! assert (x, uint8 (252)); + +%!test +%! x = nchoosek (double (10), single (5)); +%! assert (x, single (252)); + %!test <*63538> %! x = nchoosek ([1:3]', 2); %! assert (x, [1 2; 1 3; 2 3]); @@ -299,6 +313,7 @@ %!error <N must be a non-negative integer .= K> nchoosek (100, 145) %!error <N must be a non-negative integer .= K> nchoosek (-100, 45) %!error <N must be a non-negative integer .= K> nchoosek (100.5, 45) +%!error <incompatible input types> nchoosek (uint8 (15), uint16 (5)) %!warning <possible loss of precision> nchoosek (100, 45); %!warning <result .* saturated> nchoosek (uint64 (80), uint64 (40)); %!warning <result .* saturated> nchoosek (uint32 (80), uint32 (40));