Possible practical solution to your issue is rounding the final aggregate by one decimal place less than the rounding on the previous more granular level
INSERT INTO animals (animaltype, size, total)
VALUES
('Bird', 'Small', 1615),('Bird', 'Medium', 3130),('Bird', 'Large', 8120),
('Cat', 'Small', 518015),('Cat', 'Medium', 250575),('Cat', 'Large', 439490),
('Dog', 'Small', 336680),('Dog', 'Medium', 942095),('Dog', 'Large', 978115);
SELECT
animaltype,
size,
total,
percentage_exact,
percentage_rd2,
sum(percentage_exact) over () as all_perc_exact_sum,
sum(percentage_rd2) over () as all_perc_rd2_sum,
round(sum(percentage_rd2) over () ,1) as all_perc_rd2_sum_rd1
FROM
(
SELECT
animaltype,
size,
total,
100.0 * total / (SUM(total) over ()) as percentage_exact,
round(100.0 * total / (SUM(total) over ()),2) as percentage_rd2
FROM animals
) s
| animaltype | size | total | percentage_exact | percentage_rd2 | all_perc_exact_sum | all_perc_rd2_sum | all_perc_rd2_sum_rd1 |
|------------|--------|--------|----------------------|----------------|--------------------|------------------|----------------------|
| Bird | Small | 1615 | 0.046436935622305255 | 0.05 | 100 | 99.99 | 100 |
| Bird | Medium | 3130 | 0.08999851919369378 | 0.09 | 100 | 99.99 | 100 |
| Bird | Large | 8120 | 0.23347858653443881 | 0.23 | 100 | 99.99 | 100 |
| Cat | Small | 518015 | 14.89475492655632 | 14.89 | 100 | 99.99 | 100 |
| Cat | Medium | 250575 | 7.204913401584607 | 7.2 | 100 | 99.99 | 100 |
| Cat | Large | 439490 | 12.636884728573955 | 12.64 | 100 | 99.99 | 100 |
| Dog | Small | 336680 | 9.68073528502646 | 9.68 | 100 | 99.99 | 100 |
| Dog | Medium | 942095 | 27.088547904084006 | 27.09 | 100 | 99.99 | 100 |
| Dog | Large | 978115 | 28.124249712824213 | 28.12 | 100 | 99.99 | 100 |
So here round first by 2 decimal place
round(100.0 * total / (SUM(total) over ()),2) as percentage_rd2
and then round the aggregate by 1 decimal place
round(sum(percentage_2) over () ,1) as all_perc_rd2_sum_rd1