def to_scientific_string(number, frac_length=None, exp_length=None, sign_always=False):
exp_length = <NUM_LIT:0> if not exp_length else exp_length<EOL>mant, exp = to_scientific_tuple(number)<EOL>fmant = float(mant)<EOL>if (not frac_length) or (fmant == int(fmant)):<EOL><INDENT>return "<STR_LIT>".format(<EOL>sign="<STR_LIT:+>" if sign_always and (fmant >= <NUM_LIT:0>) else "<STR_LIT>",<EOL>mant=mant,<EOL>period="<STR_LIT:.>" if frac_length else "<STR_LIT>",<EOL>zeros="<STR_LIT:0>" * frac_length if frac_length else "<STR_LIT>",<EOL>exp_sign="<STR_LIT:->" if exp < <NUM_LIT:0> else "<STR_LIT:+>",<EOL>exp=str(abs(exp)).rjust(exp_length, "<STR_LIT:0>"),<EOL>)<EOL><DEDENT>rounded_mant = round(fmant, frac_length)<EOL>if abs(rounded_mant) == <NUM_LIT:10>:<EOL><INDENT>rounded_mant = fmant = -<NUM_LIT:1.0> if number < <NUM_LIT:0> else <NUM_LIT:1.0><EOL>frac_length = <NUM_LIT:1><EOL>exp = exp + <NUM_LIT:1><EOL><DEDENT>zeros = <NUM_LIT:2> + (<NUM_LIT:1> if (fmant < <NUM_LIT:0>) else <NUM_LIT:0>) + frac_length - len(str(rounded_mant))<EOL>return "<STR_LIT>".format(<EOL>sign="<STR_LIT:+>" if sign_always and (fmant >= <NUM_LIT:0>) else "<STR_LIT>",<EOL>mant=rounded_mant,<EOL>zeros="<STR_LIT:0>" * zeros,<EOL>exp_sign="<STR_LIT:->" if exp < <NUM_LIT:0> else "<STR_LIT:+>",<EOL>exp=str(abs(exp)).rjust(exp_length, "<STR_LIT:0>"),<EOL>)<EOL>
Convert number or number string to a number string in scientific notation.

Full precision is maintained if
the number is represented as a string

:param number: Number to convert
:type  number: number or string

:param frac_length: Number of digits of fractional part, None indicates
                    that the fractional part of the number should not be
                    limited
:type  frac_length: integer or None

:param exp_length: Number of digits of the exponent; the actual length of
                   the exponent takes precedence if it is longer
:type  exp_length: integer or None

:param sign_always: Flag that indicates whether the sign always
                    precedes the number for both non-negative and negative
                    numbers (True) or only for negative numbers (False)
:type  sign_always: boolean

:rtype: string

For example:

    >>> import putil.eng
    >>> putil.eng.to_scientific_string(333)
    '3.33E+2'
    >>> putil.eng.to_scientific_string(0.00101)
    '1.01E-3'
    >>> putil.eng.to_scientific_string(99.999, 1, 2, True)
    '+1.0E+02'