Alas, your last two methods put a 400K file before a 399M file... For the first one, I added a "K" key to your anonymous hash:
perl -e 'sub h{pop=~/^([\d.]+)(.)/&&{K,1e1,M,1e3,G,1e6}->{$2}+$1}print
+ sort{h($b)<=>h$a}`du -h`'
For the second one, I think you're in a bind because ord(k)&7 and ord(K)&7 are equal...
And I offer another method, bumming heavily from yours, longer but possibly faster on large filesystems:
perl -e 'print map substr($_,8),reverse sort map sprintf("%8d",(/^([\d
+.]+)([kKMG])/)?{K,1e1,M,1e3,G,1e6}->{$2}+$1:$1).$_,`du -h`'
|