Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

classlib: fix SimpleNumber asTimeString for negative values #4802

Conversation

dyfer
Copy link
Member

@dyfer dyfer commented Mar 6, 2020

Purpose and Motivation

Negative SimpleNumber -asTimeString returned incorrect string.

Previously:

-1.asTimeString;
-> 0-1:23:59:59.000

Now:

-1.asTimeString;
-> -00:00:01.000

Types of changes

  • Bug fix

To-do list

  • Code is tested
  • All tests are passing
  • This PR is ready for review

@dyfer dyfer changed the title classlib: fix SimpleNumber asTimeString classlib: fix SimpleNumber asTimeString for negative values Mar 6, 2020
Copy link
Contributor

@mossheim mossheim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks! can you please add the following test cases:

  • -0.0.asTimeString
  • -1.asTimeString(dropDaysIfPossible: false)

decimal = number.asInteger;
days = decimal.div(86400).min(maxDays);
days = if(dropDaysIfPossible and: { days == 0 }) {
days = ""
} {
days.asString.padLeft(3, "0").add($:);
};
if(isNegative, {days = "-" ++ days});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in general we use trailing closure for if in the class library. i've added a style point for that here: https://github.com/supercollider/supercollider/wiki/Code-style-guidelines#trailing-closure-syntax

can you change this one here please?

var number, decimal, days, hours, minutes, seconds, mseconds, isNegative = false;
if(this < 0, {
isNegative = true;
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be simplified to var number, decimal, days, hours, minutes, seconds, mseconds, isNegative = this < 0;

@mossheim
Copy link
Contributor

mossheim commented Mar 6, 2020

@dyfer gentle reminder to label your PRs!

@mossheim mossheim added the comp: class library SC class library label Mar 6, 2020
@dyfer
Copy link
Member Author

dyfer commented Mar 6, 2020

@dyfer gentle reminder to label your PRs!

Sorry I missed it! And thanks!

@dyfer
Copy link
Member Author

dyfer commented Mar 6, 2020

Thanks for a quick feedback!

I changed the if statement in the code that I added, but did not touch the one that was there already, should I change that too?

As for

  • -0.0.asTimeString

I'm not sure what the proper output should be. Intuitively I'd expect

-0.0.asTimeString;
-> -00:00:00.000

but since we don't seem to be able to differentiate between -0.0 and 0.0 (-0.0 == 0.0 -> true), I don't know how to achieve that. Currently this method gives

-0.0.asTimeString;
-> 00:00:00.000

In that case, should this be the expected result of the test?

@dyfer
Copy link
Member Author

dyfer commented Mar 6, 2020

...I guess I could check for identity:

-0.0 === 0.0
-> false
-0.0 === -0.0
-> true

in the method, as a special case. Is this the way to go?

edit: I added that check, let me know what you think, thanks!

@mossheim
Copy link
Contributor

mossheim commented Mar 6, 2020

I changed the if statement in the code that I added, but did not touch the one that was there already, should I change that too?

that one seems right already, not sure what you're asking

As for -0.0.asTimeString I'm not sure what the proper output should be

sorry, should have clarified. i think what it does now is fine, and actually makes more sense in my opinion as "-0" is not an intuitively sensible number for most people. this is also a lossy conversion so it's not vital to make sure everything round-trips between this and asSecs perfectly. i just want to pin that behavior so we can be aware if it changes in the future.

@dyfer
Copy link
Member Author

dyfer commented Mar 6, 2020

that one seems right already, not sure what you're asking

My bad! I was in a rush and misread the code.

sorry, should have clarified. i think what it does now is fine, and actually makes more sense in my opinion as "-0" is not an intuitively sensible number for most people. this is also a lossy conversion so it's not vital to make sure everything round-trips between this and asSecs perfectly. i just want to pin that behavior so we can be aware if it changes in the future.

Sorry, wanted to be done with this and followed that identity path. So now should I revert it and leave the behavior of

-0.0.asTimeString;
-> 00:00:00.000

?

@dyfer
Copy link
Member Author

dyfer commented Mar 6, 2020

"-00:00:00.000".asSecs;
-> -0.0

so maybe that explicit check for -0.0 should stay?

@dyfer dyfer added the bug Issues that relate to unexpected/unwanted behavior. Don't use for PRs. label Mar 6, 2020
@mossheim
Copy link
Contributor

took some time to think about this one.

i don't think we should output a timestamp saying -0, and the main reason is that while hardware makes an effort to ensure -0 and 0 as floating point values compare equal, there is no such assistance for the strings "-00:00:00" and "00:00:00". by outputting both we now put the burden on the programmer to handle this one case where two strings represent the same time stamp but do not compare equal.

furthermore, the knowledge that the input value that produced "-00:00:00" was -0 or rounded up from slightly below 0 is, in my view, of marginal utility at best, and distracting or confusing at worst.

another reason i prefer to not have a -0 is that fixed-point decimals such as these timestamps are conceptually closer to integers than floating point numbers. importantly, the interval between successive values remains fixed (like integers) rather than increasing exponentially (as with floats).

finally, in my experience the vast number of numerical comparisons are typically done with ==, for good reason -- 0 and -0 wouldn't compare equal under identity ===, but they do under equality ==. and, asTimeString followed by asSecs always produces a float regardless of whether the original number was an integer. for that reason, i think ensuring that a round trip between asTimeString and asSecs preserves identity cannot be a goal here.

so, i think this PR should be modified such that -0.0, -0.0001, etc. all produce the result 00:00:00[.000] with no negative sign. that means checking for negative values after rounding.

@dyfer
Copy link
Member Author

dyfer commented Mar 15, 2020

Thanks @brianlheim for your thoughts. I changed this PR so it is now

-0.0.asTimeString;
-> 00:00:00.000

that means checking for negative values after rounding.

AFAICT I only need to not check for identity, since

-0.0 < 0;
-> false

I'm just pointing it out to make sure I'm not doing something wrong.

@mossheim
Copy link
Contributor

AFAICT I only need to not check for identity,

you also need to handle inputs like -.001 which are negative but may round up to 0 for the requested precision. please make sure to add a test for that.

@dyfer
Copy link
Member Author

dyfer commented Mar 29, 2020

you also need to handle inputs like -.001 which are negative but may round up to 0 for the requested precision. please make sure to add a test for that.

done!

@mossheim mossheim merged commit 901bb06 into supercollider:develop Apr 4, 2020
@mossheim mossheim mentioned this pull request Apr 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issues that relate to unexpected/unwanted behavior. Don't use for PRs. comp: class library SC class library
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants