The problem here isn't necessarily that the image isn't grayscale; it's that the data isn't scaled properly for other tools to know what to do with it. Consider the scenario where you have a uint16 image cast as double(), but not rescaled.
A0 = im2uint16(imread('cameraman.tif'));
It doesn't show up against this awful white website background, but there's a totally white image there. Tools like imwrite and imshow expect data to be scaled within a specific range dependent on the class of the data. For uint16, black is 0, white is 65535; for floating-point classes, black is 0, white is 1. Since all of the data is >1, imshow treats it as white.
If viewing this denormalized image is all that's needed, you can do this
to explicitly specify the display mapping without changing the image.
Fixing the image
You could use mat2gray() to normalize the image, but that will normalize the image to its extreme values, altering the contrast of the image. The image which once contained neither black nor white has been stretched so that it does. This may be of no consequence if it's for viewing, but it may otherwise be an unacceptable and unnecessary alteration in technical contexts where the actual values matter.
If it's desired to have a floating-point image, one can simply rescale the data to suit the class
All of this could have been avoided by simply using im2double() instead of double. Unlike double(), im2double() casts and rescales the data like the prior example.