Index: sasmodels/generate.py
===================================================================
--- sasmodels/generate.py	(revision 6592f56e0e7b113bb232ebf8d0cb4c506d37fae4)
+++ sasmodels/generate.py	(revision 2e49f9e859e8f4ca13fde7469af66ddd45ae0d5f)
@@ -362,4 +362,5 @@
     for long double precision.
     """
+    source = _fix_tgmath_int(source)
     if dtype == F16:
         fbytes = 2
@@ -391,9 +392,149 @@
     source = re.sub(r'(^|[^a-zA-Z0-9_]c?)double(([248]|16)?($|[^a-zA-Z0-9_]))',
                     r'\1%s\2'%type_name, source)
+    source = _tag_float(source, constant_flag)
+    return source
+
+TGMATH_INT_RE = re.compile(r"""
+(?: # Non-capturing match; not lookbehind since pattern length is variable
+  \b              # word boundary
+   # various math functions
+  (a?(sin|cos|tan)h? | atan2
+   | erfc? | tgamma
+   | exp(2|10|m1)? | log(2|10|1p)? | pow[nr]? | sqrt | rsqrt | rootn
+   | fabs | fmax | fmin
+   )
+  \s*[(]\s*       # open parenthesis
+)
+[+-]?(0|[1-9]\d*) # integer
+(?=               # lookahead match: don't want to move from end of int
+  \s*[,)]         # comma or close parenthesis for end of argument
+)                 # end lookahead
+""", re.VERBOSE)
+def _fix_tgmath_int(source):
+    # type: (str) -> str
+    """
+    Replace f(integer) with f(integer.) for sin, cos, pow, etc.
+
+    OS X OpenCL complains that it can't resolve the type generic calls to
+    the standard math functions when they are called with integer constants,
+    but this does not happen with the Windows Intel driver for example.
+    To avoid confusion on the matrix marketplace, automatically promote
+    integers to floats if we recognize them in the source.
+
+    The specific functions we look for are:
+
+        trigonometric: sin, asin, sinh, asinh, etc., and atan2
+        exponential:   exp, exp2, exp10, expm1, log, log2, log10, logp1
+        power:         pow, pown, powr, sqrt, rsqrt, rootn
+        special:       erf, erfc, tgamma
+        float:         fabs, fmin, fmax
+
+    Note that we don't convert the second argument of dual argument
+    functions: atan2, fmax, fmin, pow, powr.  This could potentially
+    be a problem for pow(x, 2), but that case seems to work without change.
+    """
+    out = TGMATH_INT_RE.sub(r'\g<0>.', source)
+    return out
+
+
+# Floating point regular expression
+#
+# Define parts:
+#
+#    E = [eE][+-]?\d+    : Exponent
+#    P = [.]             : Decimal separator
+#    N = [1-9]\d*        : Natural number, no leading zeros
+#    Z = 0               : Zero
+#    F = \d+             : Fractional number, maybe leading zeros
+#    F? = \d*            : Optional fractional number
+#
+# We want to reject bare natural numbers and bare decimal points, so we
+# need to tediously outline the cases where we have either a fraction or
+# an exponent:
+#
+#   ( ZP | ZPF | ZE | ZPE | ZPFE | NP | NPF | NE | NPE | NPFE | PF | PFE )
+#
+#
+# We can then join cases by making parts optional.  The following are
+# some ways to do this:
+#
+#   ( (Z|N)(P|PF|E|PE|PFE) | PFE? )                   # Split on lead
+#     => ( (Z|N)(PF?|(PF?)?E) | PFE? )
+#   ( ((Z|N)PF?|PF)E? | (Z|N)E)                       # Split on point
+#   ( (ZP|ZPF|NP|NPF|PF) | (Z|ZP|ZPF|N|NP|NPF|PF)E )  # Split on E
+#     => ( ((Z|N)PF?|PF) | ((Z|N)(PF?)? | PF) E )
+FLOAT_RE = re.compile(r"""
+    (?<!\w)  # use negative lookbehind since '.' confuses \b test
+    # use split on lead to match float ( (Z|N)(PF?|(PF?)?E) | PFE? )
+    ( ( 0 | [1-9]\d* )                     # ( ( Z | N )
+      ([.]\d* | ([.]\d*)? [eE][+-]?\d+ )   #   (PF? | (PF?)? E )
+    | [.]\d+ ([eE][+-]?\d+)?               # | PF (E)?
+    )                                      # )
+    (?!\w)  # use negative lookahead since '.' confuses \b test
+    """, re.VERBOSE)
+def _tag_float(source, constant_flag):
     # Convert floating point constants to single by adding 'f' to the end,
     # or long double with an 'L' suffix.  OS/X complains if you don't do this.
-    source = re.sub(r'[^a-zA-Z_](\d*[.]\d+|\d+[.]\d*)([eE][+-]?\d+)?',
-                    r'\g<0>%s'%constant_flag, source)
-    return source
+    out = FLOAT_RE.sub(r'\g<0>%s'%constant_flag, source)
+    #print("in",repr(source),"out",repr(out), constant_flag)
+    return out
+
+def test_tag_float():
+
+    cases="""
+ZP  : 0.
+ZPF : 0.0,0.01,0.1
+Z  E: 0e+001
+ZP E: 0.E0
+ZPFE: 0.13e-031
+NP  : 1., 12.
+NPF : 1.0001, 1.1, 1.0
+N  E: 1e0, 37E-080
+NP E: 1.e0, 37.E-080
+NPFE: 845.017e+22
+ PF : .1, .0, .0100
+ PFE: .6e+9, .82E-004
+# isolated cases
+0.
+1e0
+0.13e-013
+# untouched
+struct3.e3, 03.05.67, 37
+# expressions
+3.75+-1.6e-7-27+13.2
+a3.e2 - 0.
+4*atan(1)
+4.*atan(1.)
+"""
+
+    output="""
+ZP  : 0.f
+ZPF : 0.0f,0.01f,0.1f
+Z  E: 0e+001f
+ZP E: 0.E0f
+ZPFE: 0.13e-031f
+NP  : 1.f, 12.f
+NPF : 1.0001f, 1.1f, 1.0f
+N  E: 1e0f, 37E-080f
+NP E: 1.e0f, 37.E-080f
+NPFE: 845.017e+22f
+ PF : .1f, .0f, .0100f
+ PFE: .6e+9f, .82E-004f
+# isolated cases
+0.f
+1e0f
+0.13e-013f
+# untouched
+struct3.e3, 03.05.67, 37
+# expressions
+3.75f+-1.6e-7f-27+13.2f
+a3.e2 - 0.f
+4*atan(1)
+4.f*atan(1.f)
+"""
+
+    for case_in, case_out in zip(cases.split('\n'), output.split('\n')):
+        out = _tag_float(case_in, 'f')
+        assert case_out == out, "%r => %r"%(case_in, out)
 
 
