Skip to content

Fix two rounding errors in Angle.to_string - #20227

Merged
mhvk merged 2 commits into
astropy:mainfrom
veyron-kairo:fix-sexagesimal-seconds-rounding
Aug 10, 2026
Merged

mhvk merged 2 commits into
astropy:mainfrom
veyron-kairo:fix-sexagesimal-seconds-rounding

Conversation

@veyron-kairo

@veyron-kairo veyron-kairo commented Aug 10, 2026 •

Copy link
Copy Markdown
Contributor

Split out of #20130, where @mhvk spotted the first of these.

The seconds carry into the minutes too early:

>>> Angle("1d2m59.49999s").to_string(precision=0)
'1d03m00s'          # should be 1d02m59s

The threshold sat a whole unit in the last digit shown below 60 instead of half of one. As @mhvk suggested it now rounds the seconds and compares against 60, so there is no threshold left. It does need the builtin round on a float, since numpy's scales by ten and back and calls 59.995 at precision 2 a carry where the formatting gives 59.99.

And with fields=1 the angle is rounded twice, seconds into minutes and then minutes into degrees:

>>> Angle("285d29m41.76s").to_string(fields=1)
'286d'              # should be 285d

The degrees are now rounded on the minutes and seconds together.

Over 40,000 angles per case this moves 295 for fields=1, and 365 and 19 for fields=3 at precision 0 and 1. Nothing else changes. Tests for both, checked to fail against the current code.

The carry threshold was a full unit below 60 instead of half of one, so
Angle("1d2m59.49999s").to_string(precision=0) gave 1d03m00s, not
1d02m59s. Rounding and comparing to 60 needs no threshold at all. Not
NumPy's round, which disagrees on ties like 59.995 at precision 2.

Signed-off-by: Shridhar Panigrahi <[email protected]>
With fields=1 the seconds were rounded into the minutes at 30, and the
minutes then into the degrees at 30 as well, so an angle got rounded
twice: Angle("285d29m41.76s").to_string(fields=1) gave 286d, not 285d.

Signed-off-by: Shridhar Panigrahi <[email protected]>
@github-actions

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Astropy! 🌌 This checklist is meant to remind the package maintainers who will review this pull request of some common things to look for.

  • Do the proposed changes actually accomplish desired goals?
  • Do the proposed changes follow the Astropy coding guidelines?
  • Are tests added/updated as required? If so, do they follow the Astropy testing guidelines?
  • Are docs added/updated as required? If so, do they follow the Astropy documentation guidelines?
  • Is rebase and/or squash necessary? If so, please provide the author with appropriate instructions. Also see instructions for rebase and squash.
  • Did the CI pass? If no, are the failures related? If you need to run daily and weekly cron jobs as part of the PR, please apply the "Extra CI" label. Codestyle issues can be fixed by the bot.
  • Is a change log needed? If yes, did the change log check pass? If no, add the "no-changelog-entry-needed" label. If this is a manual backport, use the "skip-changelog-checks" label unless special changelog handling is necessary.
  • Is this a big PR that makes a "What's new?" entry worthwhile and if so, is (1) a "what's new" entry included in this PR and (2) the "whatsnew-needed" label applied?
  • At the time of adding the milestone, if the milestone set requires a backport to release branch(es), apply the appropriate "backport-X.Y.x" label(s) before merge.

@mhvk mhvk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks, very nice! I wrote two nits about the examples, but thinking more about it, I think it is fine as is, since in a way your examples are things that went wrong before, where it is OK that it is obvious that what you expect is correct.

So, let me just get it in, thanks!

[
# Just below half a unit in the last digit shown: no carry.
("1d2m59.49999s", 0, "1d02m59s"),
("1d2m59.94s", 1, "1d02m59.9s"),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd add some 9 here, as in .949999

# At or above it: the seconds carry into the minutes, and on into
# the degrees.
("1d2m59.5s", 0, "1d03m00s"),
("1d2m59.96s", 1, "1d03m00.0s"),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

And here maybe .950001.

@mhvk mhvk added the Bug label Aug 10, 2026
@mhvk mhvk added this to the v8.0.2 milestone Aug 10, 2026
@mhvk mhvk added backport-v7.2.x on-merge: backport to v7.2.x backport-v8.0.x on-merge: backport to v8.0.x labels Aug 10, 2026
@mhvk mhvk modified the milestones: v8.0.2, v7.2.3 Aug 10, 2026
@mhvk
mhvk enabled auto-merge August 10, 2026 17:42
@mhvk
mhvk merged commit 41fc03d into astropy:main Aug 10, 2026
54 of 57 checks passed
pllim added a commit that referenced this pull request Aug 10, 2026
…227-on-v8.0.x

Backport PR #20227 on branch v8.0.x (Fix two rounding errors in Angle.to_string)
pllim added a commit that referenced this pull request Aug 10, 2026
…227-on-v7.2.x

Backport PR #20227 on branch v7.2.x (Fix two rounding errors in Angle.to_string)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-v7.2.x on-merge: backport to v7.2.x backport-v8.0.x on-merge: backport to v8.0.x Bug coordinates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants