Unsigned integer subtraction

Problem

You want to perform subtraction where the result is unsigned and never negative.

Solution

When a subtraction result would be negative, the answer should be zero. The following query creates a UDF that performs the calculation:

try
{
    Value result = await client.Query(
        CreateFunction(
            Obj(
                "name", "subtract_unsigned",
                "body", Query(
                    Lambda(
                        Arr("a", "b"),
                        Let(
                            "diff", Subtract(Var("a"), Var("b")),
                            "negative", Not(
                                EqualsFn(Var("diff"), Abs(Var("diff")))
                            )
                        ).In(
                            If(Var("negative"), 0, Var("diff"))
                        )
                    )
                )
            )
        )
    );
    Console.WriteLine(result);
}
catch (Exception e)
{
    Console.WriteLine($"ERROR: {e.Message}");
}
result, err := client.Query(
	f.CreateFunction(
		f.Obj{
			"name": "subtract_unsigned",
			"body": f.Query(
				f.Lambda(
					f.Arr{"a", "b"},
					f.Let().Bind(
						"diff", f.Subtract(f.Var("a"), f.Var("b")),
					).Bind(
						"negative", f.Not(
							f.Equals(f.Var("diff"), f.Abs(f.Var("diff"))),
						),
					).In(
						f.If(f.Var("negative"), 0, f.Var("diff")),
					),
				),
			),
		},
	))

if err != nil {
	fmt.Fprintln(os.Stderr, err)
} else {
	fmt.Println(result)
}
client.query(
  q.CreateFunction({
    name: 'subtract_unsigned',
    body: q.Query(
      q.Lambda(
        ['a', 'b'],
        q.Let(
          {
            diff: q.Subtract(q.Var('a'), q.Var('b')),
            negative: q.Not(q.Equals(q.Var('diff'), q.Abs(q.Var('diff')))),
          },
          q.If(q.Var('negative'), 0, q.Var('diff'))
        )
      )
    ),
  })
)
.then((ret) => console.log(ret))
.catch((err) => console.error(
  'Error: [%s] %s: %s',
  err.name,
  err.message,
  err.errors()[0].description,
))
result = client.query(
  q.create_function({
    "name": "subtract_unsigned",
    "body": q.query(
      q.lambda_(
        ["a", "b"],
        q.let(
          {
            "diff": q.subtract(q.var("a"), q.var("b")),
            "negative": q.not_(q.equals(q.var("diff"), q.abs(q.var("diff"))))
          },
          q.if_(q.var("negative"), 0, q.var("diff"))
        )
      )
    )
  })
)
print(result)
CreateFunction({
  name: "subtract_unsigned",
  body: Query(
    Lambda(
      ["a", "b"],
      Let(
        {
          diff: Subtract(Var("a"), Var("b")),
          negative: Not(Equals(Var("diff"), Abs(Var("diff"))))
        },
        If(Var("negative"), 0, Var("diff"))
      )
    )
  )
})
Query metrics:
  •    bytesIn:  296

  •   bytesOut:  398

  • computeOps:    1

  •    readOps:    0

  •   writeOps:    1

  •  readBytes:   30

  • writeBytes:  504

  •  queryTime: 37ms

  •    retries:    0

The following query calls the UDF with parameters that return a positive result:

try
{
    Value result = await client.Query(
        Call("subtract_unsigned", 123, 45)
    );
    Console.WriteLine(result);
}
catch (Exception e)
{
    Console.WriteLine($"ERROR: {e.Message}");
}
LongV(78)
result, err := client.Query(
	f.Call("subtract_unsigned", 123, 45))

if err != nil {
	fmt.Fprintln(os.Stderr, err)
} else {
	fmt.Println(result)
}
78
client.query(
  q.Call('subtract_unsigned', 123, 45)
)
.then((ret) => console.log(ret))
.catch((err) => console.error(
  'Error: [%s] %s: %s',
  err.name,
  err.message,
  err.errors()[0].description,
))
78
result = client.query(
  q.call("subtract_unsigned", 123, 45)
)
print(result)
78
Call("subtract_unsigned", 123, 45)
78
Query metrics:
  •    bytesIn:  49

  •   bytesOut:  15

  • computeOps:   1

  •    readOps:   0

  •   writeOps:   0

  •  readBytes:   0

  • writeBytes:   0

  •  queryTime: 9ms

  •    retries:   0

The following query calls the UDF with parameters that return what would have been a negative result:

try
{
    Value result = await client.Query(
        Call("subtract_unsigned", 45, 123)
    );
    Console.WriteLine(result);
}
catch (Exception e)
{
    Console.WriteLine($"ERROR: {e.Message}");
}
LongV(0)
result, err := client.Query(
	f.Call("subtract_unsigned", 45, 123))

if err != nil {
	fmt.Fprintln(os.Stderr, err)
} else {
	fmt.Println(result)
}
0
client.query(
  q.Call('subtract_unsigned', 45, 123)
)
.then((ret) => console.log(ret))
.catch((err) => console.error(
  'Error: [%s] %s: %s',
  err.name,
  err.message,
  err.errors()[0].description,
))
0
result = client.query(
  q.call("subtract_unsigned", 45, 123)
)
print(result)
0
Call("subtract_unsigned", 45, 123)
0
Query metrics:
  •    bytesIn:  49

  •   bytesOut:  14

  • computeOps:   1

  •    readOps:   0

  •   writeOps:   0

  •  readBytes:   0

  • writeBytes:   0

  •  queryTime: 2ms

  •    retries:   0

Is this article helpful? 

Tell Fauna how the article can be improved:
Visit Fauna's forums or email docs@fauna.com

Thank you for your feedback!