def compare_nfs_ecm(nfs_hours, median_curves, hours_per_curve, odds_factor_exists):
'''This is the meat, the workhorse. Everything else is a helper to precompute the arguments for
this function.
The arguments are self explanatory. The return value is either number of curves to do, or
negative if you should just do the usual ECM before proceeding to the next level.
'''
# Now we want to find the crossover where ecm-work/odds_of_success = nfs_work.
# That is, curves*work_per_curve/[odds*(1-exp(-curves/median))] = nfs_work, which is transcendental.
# Fortunately it's an analytic function with no pathologies, so a stupid Newton iteration to
# find the solution will work fine.
f = lambda curves: curves*hours_per_curve/(-expm1(-curves/median_curves)) - odds_factor_exists*nfs_hours
# ...rest of function is newton iteration to find the 0 of f