You are right there is something strange going on with doubles, what gets printed out is not the same as the contents of the variable.
for example:
groovy:000> "123.0001".toBigDecimal()
===> 123.0001
groovy:000> "123.0001".toDouble()
===> 123.0001
groovy:000> new BigDecimal("123.0001".toDouble())
===> 123.000100000000003319655661471188068389892578125
Notice the damage is done in the conversion of the string to a double, not when the double is passed into the BigDecimal. Feeding the double to the BigDecimal just provides an easy way to see what's actually in the double, because toString is lying to you.
As Jon Skeet points out, accuracy is not an option here. However, assuming the value printed out on the screen is the result of calling toString on the double, you should be able to get a bigDecimal that's no more wrong than the toString version of the double, like this:
groovy:000> d = "123.0001".toDouble()
===> 123.0001
groovy:000> d.toString()
===> 123.0001
groovy:000> new BigDecimal(d.toString())
===> 123.0001
So you don't need to involve the BigDecimal, really, you can just do something like
groovy:000> d = 123.0001
===> 123.0001
groovy:000> s = d.toString()
===> 123.0001
groovy:000> s.substring(s.indexOf('.')).length() - 1
===> 4
Sorry to invalidate your comment by editing.
BTW here's something close to Steve's answer, translated to groovy. (I took out the test for the decimal point not found because if you run this on a machine with locales messed up so it isn't using a period for the decimal point I'd rather it blow up than return 0)
def getPlaces(d) {
s = d.toString()
s.substring(s.indexOf(".")).length() - 1
}