Since ultimately the recovered time must be symbol synchronous (in the end we need one sample per symbol and that sample should be at the correct sampling location to minimize error), it would make sense to operate the timing recovery with an integer number of samples per symbol. This implies the waveform sampled at 3.9 samples per symbol could be resampled to either 2 or 4 samples per symbol. Since such resampling/ interpolation is part of timing recovery anyway, this is being done regardless! (No matter what the OP seeks to get one sample per symbol from some form of an interpolator, so if we have 1 sample per symbol, we also have two samples per symbol etc). Please refer to [this post][1] for specific details on implementing polyphase retiming filters which can operate at a non-integer number of samples per symbol and provide a properly retimed output to any precision at an integer symbol sampling rate without actually changing actual sampling clock. 

There is no requirement for general timing recovery that the sampling rate be an integer number of samples, but this is often the choice due to convenience that once recovered each subsequent $N$ samples will be at the correct timing location assuming no timing drift. Two samples per symbol is more than sufficient and often the choice in implementations using implementations such as the Gardner Loop which is my favored approach. (The OP is implementing a derivative matched filter timing recovery implementation that I have detailed in this [post][2].) Another consideration is to use a Mueller and Mueller synchronizer which only requires one sample per symbol (but must have most of the carrier offset removed from a carrier recovery loop, while the Gardner in contrast can operate with relatively large carrier offsets).  

So in summary my suggestion is to bite the bullet and resample to an integer number of samples per symbol, and use whatever precision is required in the resampler for the allowing maximum timing error by symbol (based on modulation choice and minimum EVM required). Whatever this interpolator is, is used as the timing adjustment mechanism for the actual timing loop itself. The timing error detector (Gardner or otherwise) can then operate on the retimed samples at $N$ samples per symbol with $N$ being an integer.


  [1]: https://dsp.stackexchange.com/questions/51810/symbol-timing-synchronization-using-a-high-sampling-rate/51812#51812
  [2]: https://dsp.stackexchange.com/questions/42239/how-does-this-fll-work/52163#52163