unknwon/the-way-to-go_ZH_CN · error

I won't be able to do a sqrt of negative number!

Error message

I won't be able to do a sqrt of negative number!

What it means

Error returned by MySqrt in the Chapter 6 exercise demonstrating the unnamed (value, error) return style. A real square root is undefined for negative arguments, so for f < 0 the function returns (math.NaN(), errors.New(...)) instead of a silent NaN. It teaches reporting an invalid domain through the error result rather than panicking or returning only a magic value.

Source

Thrown at eBook/exercises/chapter_6/error_returnval.go:33

	} else {
		fmt.Println("It's ok! Return values are: ", ret1, err1)
	}

	fmt.Print("Second example with 5: ")
	//you could also write it like this
	if ret2, err2 := MySqrt(5); err2 != nil {
		fmt.Println("Error! Return values are: ", ret2, err2)
	} else {
		fmt.Println("It's ok! Return values are: ", ret2, err2)
	}
	// named return variables:
	fmt.Println(MySqrt2(5))
}

func MySqrt(f float64) (float64, error) {
	//return an error as second parameter if invalid input
	if f < 0 {
		return float64(math.NaN()), errors.New("I won't be able to do a sqrt of negative number!")
	}
	//otherwise use default square root function
	return math.Sqrt(f), nil
}

//name the return variables - by default it will have 'zero-ed' values i.e. numbers are 0, string is empty, etc.
func MySqrt2(f float64) (ret float64, err error) {
	if f < 0 {
		//then you can use those variables in code
		ret = float64(math.NaN())
		err = errors.New("I won't be able to do a sqrt of negative number!")
	} else {
		ret = math.Sqrt(f)
		//err is not assigned, so it gets default value nil
	}
	//automatically return the named return variables ret and err
	return
}

View on GitHub (pinned to 7a54d34d36)

Solutions

  1. Validate the domain before calling: if f >= 0 { r, _ := MySqrt(f) } else { reject the input }
  2. If negative inputs are legitimate for your use case, switch to complex square roots: import math/cmplx and use cmplx.Sqrt(complex(f, 0))
  3. Check the error at the call site and include f in the message — NaN silently poisons later arithmetic and comparisons
  4. Clamp tiny negatives produced by rounding: if math.Abs(f) < 1e-12 { f = 0 } before the call

Example fix

// before
r, _ := MySqrt(delta) // delta = -1e-9 from rounding; r is NaN, poisons downstream math

// after
r, err := MySqrt(delta)
if err != nil {
	return fmt.Errorf("MySqrt(%g): %v", delta, err)
}
Defensive patterns

Strategy: validation

Validate before calling

if f < 0 {
	return 0, fmt.Errorf("invalid argument %g: sqrt requires f >= 0", f)
}
return MySqrt(f)

Try / catch

r, err := MySqrt(x)
if err != nil {
	return fmt.Errorf("MySqrt(%g): %v", x, err)
}
// r is a real number here

Prevention

When it happens

Trigger: Calling MySqrt with any negative float64 (e.g. MySqrt(-1)): the guard if f < 0 fires before math.Sqrt is reached. The demo main only calls MySqrt(5), so seeing this error means your own code (or your edit of the exercise) passed a negative value.

Common situations: Computing distances from deltas that can go negative through float rounding; feeding user-supplied numbers (variance, sum of squares) straight into sqrt; porting formulas whose intermediates are theoretically non-negative but drift below zero numerically; deliberately calling with -1 to test the error branch as the book's commented output shows.

Related errors


AI-assisted analysis of unknwon/the-way-to-go_ZH_CN@7a54d34d36 (2026-08-15). Data as JSON: /api/errors/66ef45d22b322640. Report an issue: GitHub.