Changeset 2e49f9e in sasmodels for sasmodels/generate.py
 Timestamp:
 Sep 12, 2016 1:41:55 AM (5 years ago)
 Branches:
 master, core_shell_microgels, costrafo411, magnetic_model, release_v0.94, release_v0.95, ticket1257vesicleproduct, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
 Children:
 80013a6
 Parents:
 b217c71
 File:

 1 edited
Legend:
 Unmodified
 Added
 Removed

sasmodels/generate.py
r6592f56 r2e49f9e 362 362 for long double precision. 363 363 """ 364 source = _fix_tgmath_int(source) 364 365 if dtype == F16: 365 366 fbytes = 2 … … 391 392 source = re.sub(r'(^[^azAZ09_]c?)double(([248]16)?($[^azAZ09_]))', 392 393 r'\1%s\2'%type_name, source) 394 source = _tag_float(source, constant_flag) 395 return source 396 397 TGMATH_INT_RE = re.compile(r""" 398 (?: # Noncapturing match; not lookbehind since pattern length is variable 399 \b # word boundary 400 # various math functions 401 (a?(sincostan)h?  atan2 402  erfc?  tgamma 403  exp(210m1)?  log(2101p)?  pow[nr]?  sqrt  rsqrt  rootn 404  fabs  fmax  fmin 405 ) 406 \s*[(]\s* # open parenthesis 407 ) 408 [+]?(0[19]\d*) # integer 409 (?= # lookahead match: don't want to move from end of int 410 \s*[,)] # comma or close parenthesis for end of argument 411 ) # end lookahead 412 """, re.VERBOSE) 413 def _fix_tgmath_int(source): 414 # type: (str) > str 415 """ 416 Replace f(integer) with f(integer.) for sin, cos, pow, etc. 417 418 OS X OpenCL complains that it can't resolve the type generic calls to 419 the standard math functions when they are called with integer constants, 420 but this does not happen with the Windows Intel driver for example. 421 To avoid confusion on the matrix marketplace, automatically promote 422 integers to floats if we recognize them in the source. 423 424 The specific functions we look for are: 425 426 trigonometric: sin, asin, sinh, asinh, etc., and atan2 427 exponential: exp, exp2, exp10, expm1, log, log2, log10, logp1 428 power: pow, pown, powr, sqrt, rsqrt, rootn 429 special: erf, erfc, tgamma 430 float: fabs, fmin, fmax 431 432 Note that we don't convert the second argument of dual argument 433 functions: atan2, fmax, fmin, pow, powr. This could potentially 434 be a problem for pow(x, 2), but that case seems to work without change. 435 """ 436 out = TGMATH_INT_RE.sub(r'\g<0>.', source) 437 return out 438 439 440 # Floating point regular expression 441 # 442 # Define parts: 443 # 444 # E = [eE][+]?\d+ : Exponent 445 # P = [.] : Decimal separator 446 # N = [19]\d* : Natural number, no leading zeros 447 # Z = 0 : Zero 448 # F = \d+ : Fractional number, maybe leading zeros 449 # F? = \d* : Optional fractional number 450 # 451 # We want to reject bare natural numbers and bare decimal points, so we 452 # need to tediously outline the cases where we have either a fraction or 453 # an exponent: 454 # 455 # ( ZP  ZPF  ZE  ZPE  ZPFE  NP  NPF  NE  NPE  NPFE  PF  PFE ) 456 # 457 # 458 # We can then join cases by making parts optional. The following are 459 # some ways to do this: 460 # 461 # ( (ZN)(PPFEPEPFE)  PFE? ) # Split on lead 462 # => ( (ZN)(PF?(PF?)?E)  PFE? ) 463 # ( ((ZN)PF?PF)E?  (ZN)E) # Split on point 464 # ( (ZPZPFNPNPFPF)  (ZZPZPFNNPNPFPF)E ) # Split on E 465 # => ( ((ZN)PF?PF)  ((ZN)(PF?)?  PF) E ) 466 FLOAT_RE = re.compile(r""" 467 (?<!\w) # use negative lookbehind since '.' confuses \b test 468 # use split on lead to match float ( (ZN)(PF?(PF?)?E)  PFE? ) 469 ( ( 0  [19]\d* ) # ( ( Z  N ) 470 ([.]\d*  ([.]\d*)? [eE][+]?\d+ ) # (PF?  (PF?)? E ) 471  [.]\d+ ([eE][+]?\d+)? #  PF (E)? 472 ) # ) 473 (?!\w) # use negative lookahead since '.' confuses \b test 474 """, re.VERBOSE) 475 def _tag_float(source, constant_flag): 393 476 # Convert floating point constants to single by adding 'f' to the end, 394 477 # or long double with an 'L' suffix. OS/X complains if you don't do this. 395 source = re.sub(r'[^azAZ_](\d*[.]\d+\d+[.]\d*)([eE][+]?\d+)?', 396 r'\g<0>%s'%constant_flag, source) 397 return source 478 out = FLOAT_RE.sub(r'\g<0>%s'%constant_flag, source) 479 #print("in",repr(source),"out",repr(out), constant_flag) 480 return out 481 482 def test_tag_float(): 483 484 cases=""" 485 ZP : 0. 486 ZPF : 0.0,0.01,0.1 487 Z E: 0e+001 488 ZP E: 0.E0 489 ZPFE: 0.13e031 490 NP : 1., 12. 491 NPF : 1.0001, 1.1, 1.0 492 N E: 1e0, 37E080 493 NP E: 1.e0, 37.E080 494 NPFE: 845.017e+22 495 PF : .1, .0, .0100 496 PFE: .6e+9, .82E004 497 # isolated cases 498 0. 499 1e0 500 0.13e013 501 # untouched 502 struct3.e3, 03.05.67, 37 503 # expressions 504 3.75+1.6e727+13.2 505 a3.e2  0. 506 4*atan(1) 507 4.*atan(1.) 508 """ 509 510 output=""" 511 ZP : 0.f 512 ZPF : 0.0f,0.01f,0.1f 513 Z E: 0e+001f 514 ZP E: 0.E0f 515 ZPFE: 0.13e031f 516 NP : 1.f, 12.f 517 NPF : 1.0001f, 1.1f, 1.0f 518 N E: 1e0f, 37E080f 519 NP E: 1.e0f, 37.E080f 520 NPFE: 845.017e+22f 521 PF : .1f, .0f, .0100f 522 PFE: .6e+9f, .82E004f 523 # isolated cases 524 0.f 525 1e0f 526 0.13e013f 527 # untouched 528 struct3.e3, 03.05.67, 37 529 # expressions 530 3.75f+1.6e7f27+13.2f 531 a3.e2  0.f 532 4*atan(1) 533 4.f*atan(1.f) 534 """ 535 536 for case_in, case_out in zip(cases.split('\n'), output.split('\n')): 537 out = _tag_float(case_in, 'f') 538 assert case_out == out, "%r => %r"%(case_in, out) 398 539 399 540
Note: See TracChangeset
for help on using the changeset viewer.