Axis flip when converting matrix4 to quaternions
No, you are not doing anything wrong. It is rotation expressed as a normalized 4-dimensional vector. Do not worry about the values there, if they need to be negative that is fine - it is still a representation of the same rotation, it is only expressed in a way that makes some math easier. It is really hard to make sense of quaternion values just by looking at them.

You can make a plane and test the rotations on it. You need to set the rotation mode to quaternion in the n panel to be able to change bpy.context.object.rotation_quaternion and see it on the object.
If you create another plane and run the script again changing the rotation in euler mode for bpy.context.object.rotation_euler instead, you will see the rotations match despite the negative values that happen to exist in a normalized 4-dimentional vector notation of the rotation. You can add this to the end of your code to see this. You will need a new object created and selected as the active object:

import bpy   
#bpy.context.object.rotation_quaternion = quat_f2
bpy.context.object.rotation_euler = euler_f2


You will be able to observe floating point/binary conversion precision errors if you decide to compare the results of quaternion to euler conversions by the numerical values doing something like this: 

print( quat_f2.to_euler() )
print( euler_f2 )


The rotations are the same. Numbers differ because of the precision errors during the calculations. That is normal.

If you need to interpolate between the quaternions you face a problem that the same rotaion can be expresed with a negative and a positive quaternion and it is possible to rotate the long way or the short way around to the same rotation. If I am reading this correctly, the short path would be between two quaternions the dot product of which would be positive, so you can check if your current rotation from the previous is the short one evaluating if the dot product of the quaternions is negative or positive and then negate your current quaternion if needed:

if quat_f1.dot(quat_f2) &lt; 0:
    quat_f2.negate()