Skip to content

Instantly share code, notes, and snippets.

@jamiebuilds
Last active December 26, 2015 12:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jamiebuilds/7148858 to your computer and use it in GitHub Desktop.
Save jamiebuilds/7148858 to your computer and use it in GitHub Desktop.
Testing different methods of calculating square-root in Sass.
/* TESTING DIFFERENT METHODS OF CALCULATING SQUARE-ROOT IN SASS */
.actual {
test-1: 1;
test-2: 1.414213562373095;
test-3: 1.732050807568877;
test-10: 3.16227766016838;
test-20: 4.47213595499958;
test-30: 5.477225575051661;
test-60: 7.745966692414834;
test-100: 10;
test-0-2: 0.447213595499958;
test--2: 'imaginary number';
test--30: 'imaginary number';
}
/* sassy-math */
.method-1-test {
test-1: 1;
test-2: 1.41421;
test-3: 1.73205;
test-10: 3.16228;
test-20: 4.47214;
test-30: 5.47723;
test-60: 7.74597;
test-100: 10;
test-0-2: 0.44721;
test--2: -1.07057;
test--30: -22.77485;
}
/* css-recipes */
.method-2-test {
test-1: 1;
test-2: 1.41421;
test-3: 1.73205;
test-10: 3.16228;
test-20: 4.47214;
test-30: 5.47723;
test-60: 7.74597;
test-100: 10;
test-0-2: 0.44721;
test--2: 1.41421;
test--30: 5.47723;
}
/* Sass-Math */
/* This method is very slow and isn't very
* accurate so I've opted to disabled it.
*/
/*
.method-3-test {
test-1: method-3-sqrt( 1);
test-2: method-3-sqrt( 2);
test-3: method-3-sqrt( 3);
test-10: method-3-sqrt( 10);
test-20: method-3-sqrt( 20);
test-30: method-3-sqrt( 30);
test-60: method-3-sqrt( 60);
test-100: method-3-sqrt(100);
test-0-2: method-3-sqrt(0.2);
test--2: method-3-sqrt( -2);
test--30: method-3-sqrt(-30);
}
*/
/* mathsass */
.method-4-test {
test-1: 1;
test-2: 1.41421;
test-3: 1.73205;
test-10: 3.16228;
test-20: 4.47214;
test-30: 5.47723;
test-60: 7.74597;
test-100: 10;
test-0-2: 0.44721;
}
/* ishango */
.method-5-test {
test-1: 1;
test-2: 1.41422;
test-3: 1.73205;
test-10: 3.16228;
test-20: 4.47214;
test-30: 5.47723;
test-60: 7.74597;
test-100: 10.0;
test-0-2: 0.44721;
}
// ----
// Sass (v3.3.0.rc.1)
// Compass (v0.13.alpha.7)
// ----
/* TESTING DIFFERENT METHODS OF CALCULATING SQUARE-ROOT IN SASS */
.actual {
test-1: 1;
test-2: 1.414213562373095;
test-3: 1.732050807568877;
test-10: 3.16227766016838;
test-20: 4.47213595499958;
test-30: 5.477225575051661;
test-60: 7.745966692414834;
test-100: 10;
test-0-2: 0.447213595499958;
test--2: 'imaginary number';
test--30: 'imaginary number';
}
// ------------------------
// Sassy-Math
// https://github.com/Team-Sass/Sassy-math/blob/master/sass/math.scss#L259
$method-1-iter: 50;
@function method-1-rand() {
@return 4;
}
@function method-1-exponent($base, $exponent) {
// reset value
$value: $base;
// positive intergers get multiplied
@if $exponent > 1 {
@for $i from 2 through $exponent {
$value: $value * $base;
}
}
// negitive intergers get divided. A number divided by itself is 1
@if $exponent < 1 {
@for $i from 0 through -$exponent {
$value: $value / $base;
}
}
// return the last value written
@return $value;
}
@function method-1-sqrt($number) {
$guess: method-1-rand();
$root: $guess;
@for $i from 1 through $method-1-iter {
$root: $root - (method-1-exponent($root, 2) - $number) / (2 * $root);
}
@return $root;
}
/* sassy-math */
.method-1-test {
test-1: method-1-sqrt( 1);
test-2: method-1-sqrt( 2);
test-3: method-1-sqrt( 3);
test-10: method-1-sqrt( 10);
test-20: method-1-sqrt( 20);
test-30: method-1-sqrt( 30);
test-60: method-1-sqrt( 60);
test-100: method-1-sqrt(100);
test-0-2: method-1-sqrt(0.2);
test--2: method-1-sqrt( -2);
test--30: method-1-sqrt(-30);
}
// ------------------------
// css-recipes
// https://github.com/css-recipes/math/blob/master/_index.scss#L67
$method-2-approximationLimit: 10;
$method-2-approximationDecimalRound: 5;
@function method-2-power($x, $exponent) {
// reset value
$value: 1;
// positive intergers get multiplied
@if $exponent >= 0 {
@for $i from 1 through $exponent {
$value: $value * $x;
}
}
// negitive intergers get divided. A number divided by itself is 1
@else {
@for $i from $exponent to 0 {
$value: $value / $x;
}
}
// return the last value written
@return $value;
}
@function method-2-decimalRound($x, $decimal: $method-2-approximationDecimalRound) {
$r: method-2-power(10, $decimal);
@return round($x * $r) / $r;
}
@function method-2-sqrt($x) {
$x: abs($x);
$guess: 4;
$root: $guess;
@for $i from 1 through $method-2-approximationLimit {
$root: $root - (method-2-power($root, 2) - $x) / (2 * $root);
}
@return method-2-decimalRound($root);
}
/* css-recipes */
.method-2-test {
test-1: method-2-sqrt( 1);
test-2: method-2-sqrt( 2);
test-3: method-2-sqrt( 3);
test-10: method-2-sqrt( 10);
test-20: method-2-sqrt( 20);
test-30: method-2-sqrt( 30);
test-60: method-2-sqrt( 60);
test-100: method-2-sqrt(100);
test-0-2: method-2-sqrt(0.2);
test--2: method-2-sqrt( -2);
test--30: method-2-sqrt(-30);
}
// ------------------------
// Sass-Math
// https://github.com/adambom/Sass-Math/blob/master/math.scss#L77
@function method-3-power($x, $n) {
$ret: 1;
@if $n >= 0 {
@for $i from 1 through $n {
$ret: $ret * $x;
}
} @else {
@for $i from $n to 0 {
$ret: $ret / $x;
}
}
@return $ret;
}
@function method-3-factorial($x) {
$ret: 1;
@if $x > 0 {
@while $x > 0 {
$ret: $ret * $x;
$x: $x - 1;
}
} @else {
$ret: 1;
}
@return $ret;
}
@function method-3-exp($x) {
$ret: 0;
@for $n from 0 to 25 {
$ret: $ret + method-3-power($x, $n) / method-3-factorial($n);
}
@return $ret;
}
@function method-3-ln($x) {
$ret: 0;
$n: 1;
$dx: .001;
@while $n <= $x {
$ret: $ret + $dx / $n;
$n: $n + $dx;
}
@return $ret;
}
@function method-3-sqrt($x) {
@return method-3-exp(0.5 * method-3-ln($x));
}
/* Sass-Math */
/* This method is very slow and isn't very
* accurate so I've opted to disabled it.
*/
/*
.method-3-test {
test-1: method-3-sqrt( 1);
test-2: method-3-sqrt( 2);
test-3: method-3-sqrt( 3);
test-10: method-3-sqrt( 10);
test-20: method-3-sqrt( 20);
test-30: method-3-sqrt( 30);
test-60: method-3-sqrt( 60);
test-100: method-3-sqrt(100);
test-0-2: method-3-sqrt(0.2);
test--2: method-3-sqrt( -2);
test--30: method-3-sqrt(-30);
}
*/
// ------------------------
// mathsass
// https://github.com/terkel/mathsass/blob/master/_math.scss#L66
@function method-4-fact($x) {
@if $x < 0 or $x != floor($x) {
@warn "Argument for `fact()` must be a positive integer.";
@return null;
}
$ret: 1;
@while $x > 0 {
$ret: $ret * $x;
$x: $x - 1;
}
@return $ret;
}
@function method-4-exp($x) {
$ret: 0;
@for $n from 0 to 24 {
$ret: $ret + method-4-pow($x, $n) / method-4-fact($n);
}
@return $ret;
}
@function method-4-pow($base, $exp) {
@if $exp == floor($exp) {
$r: 1;
$s: 0;
@if $exp < 0 {
$exp: $exp * -1;
$s: 1;
}
@while $exp > 0 {
@if $exp % 2 == 1 {
$r: $r * $base;
}
$exp: floor($exp * 0.5);
$base: $base * $base;
}
@return if($s != 0, 1 / $r, $r);
} @else {
@return method-4-exp(method-4-log($base) * $exp);
}
}
@function method-4-sqrt($x) {
@if $x < 0 {
@warn "Argument for `sqrt()` must be a positive number.";
@return null;
}
$ret: 1;
@for $i from 1 through 24 {
$ret: $ret - (method-4-pow($ret, 2) - $x) / (2 * $ret);
}
@return $ret;
}
/* mathsass */
.method-4-test {
test-1: method-4-sqrt( 1);
test-2: method-4-sqrt( 2);
test-3: method-4-sqrt( 3);
test-10: method-4-sqrt( 10);
test-20: method-4-sqrt( 20);
test-30: method-4-sqrt( 30);
test-60: method-4-sqrt( 60);
test-100: method-4-sqrt(100);
test-0-2: method-4-sqrt(0.2);
test--2: method-4-sqrt( -2);
test--30: method-4-sqrt(-30);
}
// ------------------------
// ishango
// https://github.com/nathancrank/ishango/blob/master/_ishango.scss#L460
@function method-5-exponent($value,$expN,$expD: 1) {
@if type-of($value) != number {
@debug "exponent only accepts number values for the base. Returning null.";
@return null;
}
@if ( method-5-is-int($expN) and unitless($expN) ) == false {
@debug "exponent only accepts unitless integer values for numerators. Returning null.";
@return null;
}
@if ( method-5-is-int($expD) and unitless($expD) ) == false {
@debug "exponent only accepts unitless integer values for denominators. Returning null.";
@return null;
}
$units: 1;
@if unitless($value) == false {
@if $value == 0 {
$units: $value / ( method-5-remove-unit($value) + 1);
} @else {
$units: $value / method-5-remove-unit($value);
}
$value: method-5-remove-unit($value);
}
@if $expD == 0 {
@debug "exponent(#{$value},#{$expN}, #{$expD}) results in a complex number. You can't divide by zero. Returning Null.";
@return null;
}
@if $expN == 0 { @return 1 * $units; }
@if $value == 0 { @return 0; }
@if $value < 0 and method-5-is-int($expN / $expD) == false {
@debug "exponent(#{$value},#{$expN}, #{$expD}) results in a complex number. Returning Null.";
@return null;
}
@if $expN == $expD { @return $value * $units; }
@if opp($expN) == $expD { @return ( 1 / $value ) * $units; }
$result: $value;
$neg: ($expN < 0);
$expN: abs($expN);
@for $i from 1 to $expN {
$result: $result * $value;
}
@if $expD != 1 {
@if $expD < 0 {
$expD: $expD * -1;
@if $neg { $neg: false; }
@else { $neg: true; }
}
$result: method-5-nth-root($result,$expD, true);
}
@if $neg { @return ( 1 / $result ) * $units; }
@else { @return $result * $units; }
}
@function method-5-remove-unit($value) {
@if type-of($value) != number {
@debug "You can only remove units from variables that are numbers. Returning value unchanged.";
@return $value;
}
@if unitless($value) == true { @return $value };
$units: unit($value);
@if $units == "%" { @return $value / 1%; }
@else if $units == "em" { @return $value / 1em; }
@else if $units == "rem" { @return $value / 1rem; }
@else if $units == "px" { @return $value / 1px; }
@else if $units == "in" { @return $value / 1in; }
@else if $units == "cm" { @return $value / 1cm; }
@else if $units == "mm" { @return $value / 1mm; }
@else if $units == "ex" { @return $value / 1ex; }
@else if $units == "pt" { @return $value / 1pt; }
@else if $units == "pc" { @return $value / 1pc; }
}
@function method-5-aprox-equal($value1, $value2, $prec: .00002) {
@if type-of($value1) != number {
@debug "aprox-equal only accepts number values for the comparison. Returning false.";
@return false;
}
@if type-of($value2) != number {
@debug "aprox-equal only accepts number values for the comparison. Returning false.";
@return false;
}
@if ( type-of($prec) == number and unitless($prec) ) == false {
@debug " aprox-equal $prec must be set with a unitless number values. Returning false.";
@return false;
}
@if abs($value1 - $value2) <= $prec { @return true; }
@else { @return false; }
}
@function method-5-not-aprox-equal($value1, $value2, $prec: .00002) {
@if method-5-aprox-equal($value1, $value2, $prec) { @return false; }
@else { @return true; }
}
@function method-5-nth-root($value, $n, $recursing: false) {
@if type-of($value) != number {
@debug "nth-root only accepts number values for the base. Returning null.";
@return null;
}
@if ( is-int($n) and unitless($n) ) == false {
@debug "nth-root only accepts unitless integer values for n. Returning null.";
@return null;
}
@if type-of($recursing) != bool {
@debug "Don't pass a third argument to nth-root. Returning null.";
@return null;
}
$units: 1;
@if unitless($value) == false {
@if $value == 0 {
$units: $value / ( method-5-remove-unit($value) + 1);
} @else {
$units: $value / method-5-remove-unit($value);
}
$value: method-5-remove-unit($value);
}
@if $value == 0 { @return 0; }
@if $value < 0 and $recursing == false {
@debug "method-5-nth-root(#{$value},#{$n}) results in a complex number. Returning null.";
@return null;
}
@if $n < -1 and $recursing == false { @return method-5-exponent($value, 1, $n) * $units; }
@if $n == -1 { @return ( 1 / $value ) * $units; }
@if $n == 0 { @return 1 * $units; }
$value: abs($value);
$result: $value;
$test: method-5-exponent($result, $n);
@while method-5-not-aprox-equal($value,$test) {
$result: (1 / $n) * ( ( ($n - 1) * $result) + ($value / method-5-exponent($result, $n - 1)) );
$test: method-5-exponent($result, $n);
}
@if ($n < 0) { $result: 1 / $result }
@return $result * $units;
}
@function method-5-sqrt($value) {
@return method-5-nth-root($value, 2);
}
/* ishango */
.method-5-test {
test-1: method-5-sqrt( 1);
test-2: method-5-sqrt( 2);
test-3: method-5-sqrt( 3);
test-10: method-5-sqrt( 10);
test-20: method-5-sqrt( 20);
test-30: method-5-sqrt( 30);
test-60: method-5-sqrt( 60);
test-100: method-5-sqrt(100);
test-0-2: method-5-sqrt(0.2);
test--2: method-5-sqrt( -2);
test--30: method-5-sqrt(-30);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment