Welcome to the
greediness of list construct.
The commas in the hash are pair separator. After the sprintf they become argument separator for sprintf, and without the parens it lasts until the last scalar (48 in this case). With parens, the commas as argument separator for sprintf are only before the closing paren. The closing paren itself acts as argument terminator for sprintf, separating it as an execution unit from the rest of the pairs. After the closing paren, commas become pair separator again.
Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!