I am running ArcGIS 10.5. I ginned up a quick test, and using the Python abs() function works, at least for the test.
>>> import random
>>>
>>> tmp_table = arcpy.CreateTable_management("in_memory","tmp_table")
>>>
>>> arcpy.AddField_management(tmp_table,"field_1","DOUBLE")
<Result 'in_memory\\tmp_table'>
>>> arcpy.AddField_management(tmp_table,"field_2","DOUBLE")
<Result 'in_memory\\tmp_table'>
>>> arcpy.AddField_management(tmp_table,"abs_diff","DOUBLE")
<Result 'in_memory\\tmp_table'>
>>>
>>> cur = arcpy.da.InsertCursor(tmp_table, ["field_1","field_2"])
>>> for _ in range(5):
... cur.insertRow([random.uniform(0,100), random.uniform(0,100)])
...
>>> arcpy.CalculateField_management(tmp_table,
"abs_diff",
"abs(!field_1! - !field_2!)",
"PYTHON_9.3")
....
<Result 'in_memory\\tmp_table'>
>>> arcpy.da.TableToNumPyArray(tmp_table,"*")
array([(1, 87.21215183954446, 75.1238884021629, 12.088263437381599),
(2, 45.53323645886023, 9.920800759387848, 35.61243569947235),
(3, 92.88420780744688, 63.48972631476961, 29.3944814926773),
(4, 81.26177213063858, 92.81813834079237, 11.556366210153797),
(5, 92.08135345135018, 53.952867356510815, 38.128486094839396)],
dtype=[('ObjectID', '<i4'), ('field_1', '<f8'), ('field_2', '<f8'), ('abs_diff', '<f8')])
>>>
If you create a test/example data set, are you seeing the same problem or is it specific to this data set? I did not do a join, so it could be related to that.
You say "both tables obey the same schema," do you have columns with the same names in both tables? Are you using fully qualified column names, e.g. "table1.field_1"?