// Insert change txn at random position:
vector
wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));
The problem is that size() is one in the common case of one payee, so GetRandInt will always return 0.The change ends up in the first output.
I think it should be size()+1.
Exploiting this bug I made a chart showing transaction volume of output #1 only: [CHART] Bitcoin Actual Transaction Volume? (using "change is never last" bug)
Electrum had the opposite behaviour though - it always sent the change as the last output (and as currently exists can only do single-destination transactions, so the change was always the second output if there was change). So guessing change still means guessing what the client used to send the transaction was, which helps anonymity a bit from the date electrum was released.
So I can't agree with you that your results are meaningful.
The most recent 1.6.2 release of Electrum randomizes the change output.
Also, I know some people deliberately send transactions with excess precision to the real output to make the change output have less precision and look like it isn't change.
I really think it's near-impossible to reliably guess the change output if it's not a 0.01xxx amount.
Thanks for pointing out the electrum behavior.
There could be many useful heuristics which, especially when taken together, might yield good results. I'm not going to attempt any such thing and just agree with you that it can't reliably be done.