Jump to content

Double Slider Problem


MJW
 Share

Recommended Posts

I've encountered a strange problem with the Double Slider control. It's in a fairly large VS project, and the problem seems to be confined to the single control, so for now I'll just show the relevant lines. The only code that's changed from when it seemed to work correctly is the precision in configure code.

 

The add code is:

 props.Add(new DoubleProperty(PropertyNames.TexHeightScale, 10, 0, 255));

The configure code is:

 configUI.SetPropertyControlValue(PropertyNames.TexHeightScale, ControlInfoPropertyNames.DisplayName, "Texture Height Scale");
 configUI.SetPropertyControlValue(PropertyNames.TexHeightScale, ControlInfoPropertyNames.SliderLargeChange, 0.25);
 configUI.SetPropertyControlValue(PropertyNames.TexHeightScale, ControlInfoPropertyNames.SliderSmallChange, 0.05);
 configUI.SetPropertyControlValue(PropertyNames.TexHeightScale, ControlInfoPropertyNames.UpDownIncrement, 0.01);
 configUI.SetPropertyControlValue(PropertyNames.TexHeightScale, ControlInfoPropertyNames.DecimalPlaces, 2);

What happens is that the control displays correctly, with a default of 10 and two decimal places, but if I click the up increment arrow, it increments correctly till it reaches 10.03, then it will go no further. If I try to type in 10.04, it changes it to 10.03. If I set it to 10.05 and then press the decrement arrow, it skips to 10.03. It just plain doesn't like 10.04.

 

The only thing that's different from a version which seems to work is the precision. I have an old CodeLab version of Texture Shader, built almost exactly a year ago, before CodeLab increased the number of decimal places from two to three, and it has the same problem. (Though I don't see the problem with three place precision, it could occur on other values I haven't tried to set the control to.)

Link to comment
Share on other sites

I'm pretty sure this has to do with the inaccuracy of converting from binary to floating point numbers.

There are just some numbers the computer doesn't like.

I seem to recall posting about this once before. Let's see if I can find it...

Click to play:
j.pngs.pngd.pnga.pngp.png
Download: BoltBait's Plugin Pack | CodeLab | and how about a Computer Dominos Game

Link to comment
Share on other sites

You could probably test that with a small C# program. (LINQpad is awesome for this, btw)

decimal valueInc = 0.01;
decimal value1 = 10.0;
decimal value2 = value1 + valueInc;
decimal value3 = value2 + valueInc;
decimal value4 = value3 + valueInc;
decimal value5 = value4 + valueInc;
Console.WriteLine("{0}, {1}, {2}, {3}, {4}", value1, value2, value3, value4, value5);
 
 

 

Edit: argh. code editing is terrible in current version of forum software ... you get the point

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

I may be missing something, but I would think there are two ways the control could operate: either it keeps the value as a float or double which is not adjusted for the precision, adds the increment, and display a rounded or truncated version in the control; or it keeps a version of the value which is converted to the selected precision, adds the increment, then adjusts by some form of rounding to convert it to the specified precision. In the first case, it shouldn't get stuck, though it might skip over a number or take two clicks to get past it. If it's the second case, any reasonable rounding method should cure the problem.

 

Don't Forms controls use decimal format? If so, there shouldn't be a problem with non-representable decimal values.

 

EDIT: My reply was to BoltBait's comment. I hadn't yet read Rick's. I'll try to see iif the problem is with the way C# does decimal arithmetic, though it seems unlikely such an egregious problem would have escaped notice.

Link to comment
Share on other sites

I discovered that if I change the increment to 0.01000000000001, it doesn't get stuck at 10.03. I can't say for certain that it won't get stuck at some other value. The value I gave is the smallest change I tried that eliminates the problem at 10.03.

Link to comment
Share on other sites

The built-in effect "Effects > Noise > Reduce Noise" shows this error.

Click on the strength slider. Press up arrow one at a time until you reach 0.57. Press up arrow again. Notice the slider stays at 0.57. Press it one more time and notice it jumps to 0.59.

Click to play:
j.pngs.pngd.pnga.pngp.png
Download: BoltBait's Plugin Pack | CodeLab | and how about a Computer Dominos Game

Link to comment
Share on other sites

Because the control internally uses decimal arithmetic, I think the problem must be in the conversion of the increment from double to decimal. If so, perhaps slightly increasing the increment value before conversion, by adding a small amount or multiplying by a value slightly larger than one, would prevent the problem. I wish I understood the underlying cause. None of my theories so far would result in decimal-based controls getting stuck.

Link to comment
Share on other sites

The built-in effect "Effects > Noise > Reduce Noise" shows this error.

Click on the strength slider. Press up arrow one at a time until you reach 0.57. Press up arrow again. Notice the slider stays at 0.57. Press it one more time and notice it jumps to 0.59.

 

That's interesting. That behavior -- skipping over a value -- is more what I'd expect. With my example, I can press the increment button till the cows come home and it never changes from 10.03.

Link to comment
Share on other sites

It's probably a rounding glitch.

 

0.01 can't be exactly represented by any floating point system. It is not expressible as a polynomial composed of 2^x components, where 'x' is an integer (zero and negative are permitted). For instance, 0.5 is 2^-1. More info: https://en.wikipedia.org/wiki/Floating_point#Accuracy_problems

 

(decimal)0.01 is probably rounding to an actual value less than 0.01.

  • Upvote 2

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

I don't quite understand how a mere rounding error causes the problem. Suppose the 0.01 is converted to a decimal increment slightly less than 0.01. The effect of that seems like it would be that for some value an extra click would be required to go past that value. And with any decent rounding, even that seems unlikely. Also, if the error shows up after adding the increment four times to 10 (which has an exact representation in double and decimal), I would expect it to show up repeatedly. But it doesn't seem to. I'm still confused.

Link to comment
Share on other sites

At the risk of saying something that makes no sense, I wonder if PDN (perhaps as part of synchronizing the slider with the UpDown control) reads the UpDown control as a double when it gets a value-changed event, processes it somehow, perhaps clamping it to valid values, then writes it to both controls. Normally, the same value gets written back to the UpDown, but for some cases, the wrong value is written. That's the sort of thing I can see causing the stuck-at-10.03 problem. I can't see how something internal to the UpDown control could cause the problem, because at that point, the arithmetic is all decimal.

Link to comment
Share on other sites

For what it's worth, it's not the increment value that's the problem; it's the value in the control. The built-in Render>Julia Fractal uses an increment of 1 in the Zoom. If a Zoom of 11.04 is typed in then decremented, the value goes to 10.03. Other values that fail in the double slider are 8.04, 8.79, 9.04, and 9.79. Those values will also decrement by 0.01 when typed in. The Angle control, which also uses an UpDown control, doesn't appear to be bothered by them.

 

(This result is consistent with my previous conjecture, though that may not prove much.)

 

ADDED: If the default value is set to 10.04, it will show up as 10.03.

Link to comment
Share on other sites

I wrote a test program with the following controls:

 

OnCreatePropertyCollection:

    props.Add(new BooleanProperty("testlink", true));
    props.Add(new DoubleProperty("test1", 10, 0, 20));
    props.Add(new DoubleProperty("test2", 10, 0, 20));
    propRules.Add(new LinkValuesBasedOnBooleanRule<double, DoubleProperty>(new string[] { "test1", "test2" }, "testlink", false));

OnCreateConfigUI:


    configUI.SetPropertyControlValue("testlink", ControlInfoPropertyNames.DisplayName, string.Empty);
    configUI.SetPropertyControlValue("testlink", ControlInfoPropertyNames.Description, "Link Controls");
    configUI.SetPropertyControlValue("test1", ControlInfoPropertyNames.DisplayName, "Test 1");
    configUI.SetPropertyControlValue("test1", ControlInfoPropertyNames.SliderLargeChange, 0.25);
    configUI.SetPropertyControlValue("test1", ControlInfoPropertyNames.SliderSmallChange, 0.05);
    configUI.SetPropertyControlValue("test1", ControlInfoPropertyNames.UpDownIncrement, 0.01);
    configUI.SetPropertyControlValue("test1", ControlInfoPropertyNames.DecimalPlaces, 2);
    configUI.SetPropertyControlValue("test2", ControlInfoPropertyNames.DisplayName, "Test 2");
    configUI.SetPropertyControlValue("test2", ControlInfoPropertyNames.SliderLargeChange, 0.25);
    configUI.SetPropertyControlValue("test2", ControlInfoPropertyNames.SliderSmallChange, 0.05);
    configUI.SetPropertyControlValue("test2", ControlInfoPropertyNames.UpDownIncrement, 0.0001);
    configUI.SetPropertyControlValue("test2", ControlInfoPropertyNames.DecimalPlaces, 4);

This creates two linked double slider controls, one showing two places, the other four.

 

I found several interesting things.

 

The controls show the rounded internal value, so that even if the value in the control was slightly less than 10.04, the control would show 10.04.

 

If I set the 2-place control to a value greater than 10.04 then decrement it down, the 4-place control jumps from 10.0500 to 10.0300.

 

If (while running under the VS debugger) I increment the 4-place control up to 10.0300, the next increment results in a very persistent freeze. Not only does PDN freeze; VS also freezes. After a few minutes it returns an exception:

System.StackOverflowException was unhandled
  HResult=-2147023895
  Message=Exception of type 'System.StackOverflowException' was thrown.
  InnerException:

It says the file LinkValuesBasedOnBooleanRules`2.cs not found.

(I would assume this freeze is a symptom, and not the cause of the problem.)

 

If I try to set the 4-place to control to any value greater than10.03 but less than or equal to 10.04, I get a "Paint.net quit working" error.

 

If I set the 4-place value to 10.002 and increment or decrement the 2-place control, the extra 0.002 remains in the 4-place control until the upper control is 10.03. At that point, the 4-place control goes to 10.0300.

 

If the controls are not linked, the 4-place control can accept the values without a problem, either typed in or by incrementing.

 

If the controls aren't link, and I set the 4-place control to 10.035, if link the controls (as might be expected by now), PDN freezes.

 

If by default the controls are unlinked, and I set the default of the 2-place control to 10.035, then linking the controls with the checkbox shows that the 2-place control was initialized to 10.03. If I set the 2-place control's default to 10.025, that's what appears in the 4-place control upon linking.  I think this might show a good debugging opportunity, since it just invokes tracing through the control-initialization steps to see how the value changes from 10.035 to 10.03.

 

My tentative conclusion is that double slider controls normally maintain full precision of the current value, but for some reason when the precision is 2, they truncate values between 10.03 and 10.04 to 10.03. I'm surprised the ill-behaved range seems to be based on the decimal representation, not the binary.

  • Upvote 1
Link to comment
Share on other sites

In my Psychocolour effect, using Pdn 4.09 and the up arrow, the double slider also gets stuck at 8.03, 8.28, 8.53, 8.78, 9.03, 9.28, 9.53, 9.78 as well as 10.03.

It is fine from 0 to 8.03 and from 10.03 to 15.99 (the max in that effect).

Slightly flippantly, I should have used an integer slider from 0 to 1599 for that effect. ;)

  • Upvote 1

 

Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings

 

PdnForumSig2.jpg

Link to comment
Share on other sites

Actually I reported it to TechnoRobbo as something I had noticed on Psychocolour in relevance to another plugin we (the Dwarves!;-)) were working on.
I thought it was just 'my' problem but he confirmed and reported to BoltBait - who posted the problem.

Solving problems (generally): I've never understood debugging (I know, but I'm an amateur!), BUT finding patterns in the problem is often useful.
I'm foxed by the range of problematic values - why not 7.03 or 11.03?
I like (love) things to be exact, effecient and precise but on the up side it could explain why the weather forecasts are always wrong, dark matter and dark energy!
Very worrying if floating point values are that much astray... lucky the Moon is a big target!
So, something odd is happening between 7 and 12 - why is that different to other values, bearing in mind Rick's linked Wiki post.



- it's 'Brexit' night (whisky opened  :D ) - I love Europe/Europeans/all people of the World etc. etc. but prefer democracy.
Any strong economy will suck people towards it, as cities did in the industrial revoloution.
Personally, I find it difficult to be threatened by some idiot that calls himself obama? (doesn't deserve a capital or capitol letter)
Does he espouse the idea of the U.S.A coming back under British rule?... thought not!....hypocrite!.... mini rant :roll: ....sorry. ;)  

 

Freedom! B) (I do hope so) :/ 

  • Upvote 1

 

Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings

 

PdnForumSig2.jpg

Link to comment
Share on other sites

The following trick seems to prevent the problem for values from 0.0 to 100.0. I don't like it though, and hope the bug is fixed. (And I believe it is a bug -- very likely in PDN -- not some you've-just-got-to-live-with-it floating-point precision limitation.)

        const double IncAdj = 1.00000000001;  // Adjustment to attempt to cure a problem when the double slider increments.
        protected override ControlInfo OnCreateConfigUI(PropertyCollection props)
        {
            ControlInfo configUI = CreateDefaultConfigUI(props);

            configUI.SetPropertyControlValue(PropertyNames.TexHeightScale, ControlInfoPropertyNames.DisplayName, "Texture Height Scale");
            configUI.SetPropertyControlValue(PropertyNames.TexHeightScale, ControlInfoPropertyNames.SliderLargeChange, IncAdj * 0.25);
            configUI.SetPropertyControlValue(PropertyNames.TexHeightScale, ControlInfoPropertyNames.SliderSmallChange, IncAdj * 0.05);
            configUI.SetPropertyControlValue(PropertyNames.TexHeightScale, ControlInfoPropertyNames.UpDownIncrement, IncAdj * 0.01);
            configUI.SetPropertyControlValue(PropertyNames.TexHeightScale, ControlInfoPropertyNames.DecimalPlaces, 2);

Link to comment
Share on other sites

Yeah I'm going to take a look at this. Thanks for the in-depth report and analyses!

 

I think the SliderPropertyControl is at fault here. It's bouncing things between decimal and double and it should really keep things as decimal for as long as possible. (or ... something)

 

I wouldn't really be bothered if it skipped a value here and there, and sparsely, e.g., 0.08 through 3.79 is fine, but then it mysteriously skips ahead to 3.81. But getting *stuck*, and frequently, is a really bad, lame experience.

  • Upvote 1

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

Okay I believe I have a fix for this.

 

10.04 needs to gets converted to 1004 to store into the slider's integer Value property. However, apparently 10.04 * 100.0 = 1003.999999999999999. Then this truncates to 1003.

 

Slapping a Math.Round in there should work ...

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

Does the slider keep the value as an integer? That seems at odds with its behavior. If I set the increment of a two-place double slider to 0.0025, it will increment the number display once for every four clicks. That's not how I would expect it to behave if it were scaled to an integer based on the precision. I believe the internal format is decimal, which is base-10 floating point, and that internally, the UpDown control's behavior doesn't depend on the precision. The effect of having a very slightly too small value should be invisible, since the control displays a rounded version of its internal value.

 

I still lean toward the hypothesis that in the click event handling, PDN reads the value out of the UpDown control, then writes a modified version back in. For some reason, when the number is within the sticking range, the value written back is less than or equal to the pre-incremented value. It sticks (according to this conjecture) because the event processing undoes the UpDown counter's increment. My guess is that reading and writing the control is associated with slider synchronization.

Link to comment
Share on other sites

The numeric up/down uses decimal. The slider's Value property is an integer. Fixed point math is used to convert between the two with a precision specified by DecimalPlaces. e.g. 3.987 with DecimalPlaces = 3 is encoded as 3987 for the slider.

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

I'm obviously confused, but I can't quite understand the relationship between the integer Value property and the fact that if the increment for a two-place slider is set to 0.0025, the counter will increment every fourth click. That would seem to suggest that sometimes the counter is updated from the Value property, and other times it isn't. Which could, of course, be part of the problem.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...