40 interface |
40 interface |
41 |
41 |
42 {$IFDEF FPC} |
42 {$IFDEF FPC} |
43 {$IFDEF ENDIAN_LITTLE} |
43 {$IFDEF ENDIAN_LITTLE} |
44 type hwFloat = record |
44 type hwFloat = record |
45 isNegative: boolean; |
45 isNegative: boolean; |
46 case byte of |
46 case byte of |
47 0: (Frac, Round: Longword); |
47 0: (Frac, Round: Longword); |
48 1: (QWordValue : QWord); |
48 1: (QWordValue : QWord); |
49 end; |
49 end; |
50 {$ELSE} |
50 {$ELSE} |
51 type hwFloat = record |
51 type hwFloat = record |
52 isNegative: boolean; |
52 isNegative: boolean; |
53 case byte of |
53 case byte of |
54 0: (Round, Frac: Longword); |
54 0: (Round, Frac: Longword); |
55 1: (QWordValue : QWord); |
55 1: (QWordValue : QWord); |
56 end; |
56 end; |
57 {$ENDIF} |
57 {$ENDIF} |
58 |
58 |
59 // Returns an hwFloat that represents the value of integer parameter i |
59 // Returns an hwFloat that represents the value of integer parameter i |
60 function int2hwFloat (const i: LongInt) : hwFloat; inline; |
60 function int2hwFloat (const i: LongInt) : hwFloat; inline; |
61 function hwFloat2Float (const i: hwFloat) : extended; inline; |
61 function hwFloat2Float (const i: hwFloat) : extended; inline; |
198 end; |
198 end; |
199 |
199 |
200 function hwFloat2Float (const i: hwFloat) : extended; |
200 function hwFloat2Float (const i: hwFloat) : extended; |
201 begin |
201 begin |
202 hwFloat2Float:= i.QWordValue / $100000000; |
202 hwFloat2Float:= i.QWordValue / $100000000; |
203 if i.isNegative then hwFloat2Float:= -hwFloat2Float; |
203 if i.isNegative then |
|
204 hwFloat2Float:= -hwFloat2Float; |
204 end; |
205 end; |
205 |
206 |
206 operator = (const z1, z2: hwFloat) z : boolean; inline; |
207 operator = (const z1, z2: hwFloat) z : boolean; inline; |
207 begin |
208 begin |
208 z:= (z1.isNegative = z2.isNegative) and (z1.QWordValue = z2.QWordValue); |
209 z:= (z1.isNegative = z2.isNegative) and (z1.QWordValue = z2.QWordValue); |
210 |
211 |
211 |
212 |
212 operator + (const z1, z2: hwFloat) z : hwFloat; |
213 operator + (const z1, z2: hwFloat) z : hwFloat; |
213 begin |
214 begin |
214 if z1.isNegative = z2.isNegative then |
215 if z1.isNegative = z2.isNegative then |
215 begin |
216 begin |
216 z.isNegative:= z1.isNegative; |
217 z.isNegative:= z1.isNegative; |
217 z.QWordValue:= z1.QWordValue + z2.QWordValue |
218 z.QWordValue:= z1.QWordValue + z2.QWordValue |
218 end |
219 end |
219 else |
220 else |
220 if z1.QWordValue > z2.QWordValue then |
221 if z1.QWordValue > z2.QWordValue then |
221 begin |
222 begin |
222 z.isNegative:= z1.isNegative; |
223 z.isNegative:= z1.isNegative; |
223 z.QWordValue:= z1.QWordValue - z2.QWordValue |
224 z.QWordValue:= z1.QWordValue - z2.QWordValue |
224 end else |
225 end |
225 begin |
226 else |
226 z.isNegative:= z2.isNegative; |
227 begin |
227 z.QWordValue:= z2.QWordValue - z1.QWordValue |
228 z.isNegative:= z2.isNegative; |
228 end |
229 z.QWordValue:= z2.QWordValue - z1.QWordValue |
|
230 end |
229 end; |
231 end; |
230 |
232 |
231 operator - (const z1, z2: hwFloat) z : hwFloat; |
233 operator - (const z1, z2: hwFloat) z : hwFloat; |
232 begin |
234 begin |
233 if z1.isNegative = z2.isNegative then |
235 if z1.isNegative = z2.isNegative then |
234 if z1.QWordValue > z2.QWordValue then |
236 if z1.QWordValue > z2.QWordValue then |
235 begin |
237 begin |
236 z.isNegative:= z1.isNegative; |
238 z.isNegative:= z1.isNegative; |
237 z.QWordValue:= z1.QWordValue - z2.QWordValue |
239 z.QWordValue:= z1.QWordValue - z2.QWordValue |
238 end else |
240 end |
239 begin |
241 else |
240 z.isNegative:= not z2.isNegative; |
242 begin |
241 z.QWordValue:= z2.QWordValue - z1.QWordValue |
243 z.isNegative:= not z2.isNegative; |
242 end |
244 z.QWordValue:= z2.QWordValue - z1.QWordValue |
243 else begin |
245 end |
244 z.isNegative:= z1.isNegative; |
246 else |
245 z.QWordValue:= z1.QWordValue + z2.QWordValue |
247 begin |
246 end |
248 z.isNegative:= z1.isNegative; |
|
249 z.QWordValue:= z1.QWordValue + z2.QWordValue |
|
250 end |
247 end; |
251 end; |
248 |
252 |
249 operator - (const z1: hwFloat) z : hwFloat; |
253 operator - (const z1: hwFloat) z : hwFloat; |
250 begin |
254 begin |
251 z:= z1; |
255 z:= z1; |
254 |
258 |
255 |
259 |
256 operator * (const z1, z2: hwFloat) z : hwFloat; |
260 operator * (const z1, z2: hwFloat) z : hwFloat; |
257 begin |
261 begin |
258 z.isNegative:= z1.isNegative xor z2.isNegative; |
262 z.isNegative:= z1.isNegative xor z2.isNegative; |
259 z.QWordValue:= QWord(z1.Round) * z2.Frac + |
263 z.QWordValue:= QWord(z1.Round) * z2.Frac + QWord(z1.Frac) * z2.Round + ((QWord(z1.Frac) * z2.Frac) shr 32); |
260 QWord(z1.Frac) * z2.Round + |
|
261 ((QWord(z1.Frac) * z2.Frac) shr 32); |
|
262 z.Round:= z.Round + QWord(z1.Round) * z2.Round; |
264 z.Round:= z.Round + QWord(z1.Round) * z2.Round; |
263 end; |
265 end; |
264 |
266 |
265 operator * (const z1: hwFloat; const z2: LongInt) z : hwFloat; |
267 operator * (const z1: hwFloat; const z2: LongInt) z : hwFloat; |
266 begin |
268 begin |
273 begin |
275 begin |
274 z.isNegative:= z1.isNegative xor z2.isNegative; |
276 z.isNegative:= z1.isNegative xor z2.isNegative; |
275 z.Round:= z1.QWordValue div z2.QWordValue; |
277 z.Round:= z1.QWordValue div z2.QWordValue; |
276 t:= z1 - z2 * z.Round; |
278 t:= z1 - z2 * z.Round; |
277 if t.QWordValue = 0 then |
279 if t.QWordValue = 0 then |
278 z.Frac:= 0 |
280 z.Frac:= 0 |
279 else |
281 else |
280 begin |
282 begin |
281 while ((t.QWordValue and $8000000000000000) = 0) and |
283 while ((t.QWordValue and $8000000000000000) = 0) and ((z2.QWordValue and $8000000000000000) = 0) do |
282 ((z2.QWordValue and $8000000000000000) = 0) do |
284 begin |
283 begin |
285 t.QWordValue:= t.QWordValue shl 1; |
284 t.QWordValue:= t.QWordValue shl 1; |
286 z2.QWordValue:= z2.QWordValue shl 1 |
285 z2.QWordValue:= z2.QWordValue shl 1 |
287 end; |
286 end; |
288 if z2.Round > 0 then |
287 if z2.Round > 0 then z.Frac:= (t.QWordValue) div (z2.Round) |
289 z.Frac:= (t.QWordValue) div (z2.Round) |
288 else z.Frac:= 0 |
290 else |
289 end |
291 z.Frac:= 0 |
|
292 end |
290 end; |
293 end; |
291 |
294 |
292 operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat; |
295 operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat; |
293 begin |
296 begin |
294 z.isNegative:= z1.isNegative xor (z2 < 0); |
297 z.isNegative:= z1.isNegative xor (z2 < 0); |
296 end; |
299 end; |
297 |
300 |
298 operator < (const z1, z2: hwFloat) b : boolean; |
301 operator < (const z1, z2: hwFloat) b : boolean; |
299 begin |
302 begin |
300 if z1.isNegative xor z2.isNegative then |
303 if z1.isNegative xor z2.isNegative then |
301 b:= z1.isNegative |
304 b:= z1.isNegative |
302 else |
305 else |
303 if z1.QWordValue = z2.QWordValue then |
306 if z1.QWordValue = z2.QWordValue then |
304 b:= false |
307 b:= false |
305 else |
308 else |
306 b:= (z1.QWordValue < z2.QWordValue) xor z1.isNegative |
309 b:= (z1.QWordValue < z2.QWordValue) xor z1.isNegative |
307 end; |
310 end; |
308 |
311 |
309 operator > (const z1, z2: hwFloat) b : boolean; |
312 operator > (const z1, z2: hwFloat) b : boolean; |
310 begin |
313 begin |
311 if z1.isNegative xor z2.isNegative then |
314 if z1.isNegative xor z2.isNegative then |
312 b:= z2.isNegative |
315 b:= z2.isNegative |
313 else |
316 else |
314 if z1.QWordValue = z2.QWordValue then |
317 if z1.QWordValue = z2.QWordValue then |
315 b:= false |
318 b:= false |
316 else |
319 else |
317 b:= (z1.QWordValue > z2.QWordValue) xor z2.isNegative |
320 b:= (z1.QWordValue > z2.QWordValue) xor z2.isNegative |
318 end; |
321 end; |
319 |
322 |
320 function cstr(const z: hwFloat): shortstring; |
323 function cstr(const z: hwFloat): shortstring; |
321 var tmpstr: shortstring; |
324 var tmpstr: shortstring; |
322 begin |
325 begin |
323 str(z.Round, cstr); |
326 str(z.Round, cstr); |
324 if z.Frac <> 0 then |
327 if z.Frac <> 0 then |
325 begin |
328 begin |
326 str(z.Frac / $100000000, tmpstr); |
329 str(z.Frac / $100000000, tmpstr); |
327 delete(tmpstr, 1, 2); |
330 delete(tmpstr, 1, 2); |
328 cstr:= cstr + '.' + copy(tmpstr, 1, 10) |
331 cstr:= cstr + '.' + copy(tmpstr, 1, 10) |
329 end; |
332 end; |
330 if z.isNegative then cstr:= '-' + cstr |
333 if z.isNegative then |
|
334 cstr:= '-' + cstr |
331 end; |
335 end; |
332 |
336 |
333 function hwRound(const t: hwFloat): LongInt; |
337 function hwRound(const t: hwFloat): LongInt; |
334 begin |
338 begin |
335 if t.isNegative then hwRound:= -(t.Round and $7FFFFFFF) |
339 if t.isNegative then |
336 else hwRound:= t.Round and $7FFFFFFF |
340 hwRound:= -(t.Round and $7FFFFFFF) |
|
341 else |
|
342 hwRound:= t.Round and $7FFFFFFF |
337 end; |
343 end; |
338 |
344 |
339 function hwAbs(const t: hwFloat): hwFloat; |
345 function hwAbs(const t: hwFloat): hwFloat; |
340 begin |
346 begin |
341 hwAbs:= t; |
347 hwAbs:= t; |
343 end; |
349 end; |
344 |
350 |
345 function hwSqr(const t: hwFloat): hwFloat; |
351 function hwSqr(const t: hwFloat): hwFloat; |
346 begin |
352 begin |
347 hwSqr.isNegative:= false; |
353 hwSqr.isNegative:= false; |
348 hwSqr.QWordValue:= |
354 hwSqr.QWordValue:= ((QWord(t.Round) * t.Round) shl 32) + QWord(t.Round) * t.Frac * 2 + ((QWord(t.Frac) * t.Frac) shr 32); |
349 ((QWord(t.Round) * t.Round) shl 32) |
|
350 + QWord(t.Round) * t.Frac * 2 |
|
351 + ((QWord(t.Frac) * t.Frac) shr 32); |
|
352 end; |
355 end; |
353 |
356 |
354 function hwSqrt(const t: hwFloat): hwFloat; |
357 function hwSqrt(const t: hwFloat): hwFloat; |
355 var l, r: QWord; |
358 var l, r: QWord; |
356 c: hwFloat; |
359 c: hwFloat; |
357 begin |
360 begin |
358 hwSqrt.isNegative:= false; |
361 hwSqrt.isNegative:= false; |
359 |
362 |
360 if t.Round = 0 then |
363 if t.Round = 0 then |
361 begin |
364 begin |
362 l:= t.QWordValue; |
365 l:= t.QWordValue; |
363 r:= $100000000 |
366 r:= $100000000 |
364 end else |
367 end |
365 begin |
368 else |
366 l:= $100000000; |
369 begin |
367 r:= t.QWordValue div 2 + $80000000; // r:= t / 2 + 0.5 |
370 l:= $100000000; |
368 if r > $FFFFFFFFFFFF then r:= $FFFFFFFFFFFF |
371 r:= t.QWordValue div 2 + $80000000; // r:= t / 2 + 0.5 |
369 end; |
372 if r > $FFFFFFFFFFFF then |
|
373 r:= $FFFFFFFFFFFF |
|
374 end; |
370 |
375 |
371 repeat |
376 repeat |
372 c.QWordValue:= (l + r) div 2; |
377 c.QWordValue:= (l + r) div 2; |
373 if hwSqr(c).QWordValue > t.QWordValue then r:= c.QWordValue else l:= c.QWordValue |
378 if hwSqr(c).QWordValue > t.QWordValue then |
|
379 r:= c.QWordValue |
|
380 else |
|
381 l:= c.QWordValue |
374 until r - l <= 1; |
382 until r - l <= 1; |
375 |
383 |
376 hwSqrt.QWordValue:= l |
384 hwSqrt.QWordValue:= l |
377 end; |
385 end; |
378 |
386 |
393 end; |
401 end; |
394 |
402 |
395 function hwSign(r: hwFloat): LongInt; |
403 function hwSign(r: hwFloat): LongInt; |
396 begin |
404 begin |
397 // yes, we have negative zero for a reason |
405 // yes, we have negative zero for a reason |
398 if r.isNegative then hwSign:= -1 else hwSign:= 1 |
406 if r.isNegative then |
|
407 hwSign:= -1 |
|
408 else |
|
409 hwSign:= 1 |
399 end; |
410 end; |
400 |
411 |
401 |
412 |
402 function AngleSin(const Angle: Longword): hwFloat; |
413 function AngleSin(const Angle: Longword): hwFloat; |
403 begin |
414 begin |
404 //TryDo((Angle >= 0) and (Angle <= 2048), 'Sin param exceeds limits', true); |
415 //TryDo((Angle >= 0) and (Angle <= 2048), 'Sin param exceeds limits', true); |
405 AngleSin.isNegative:= false; |
416 AngleSin.isNegative:= false; |
406 if Angle < 1024 then AngleSin.QWordValue:= SinTable[Angle] |
417 if Angle < 1024 then |
407 else AngleSin.QWordValue:= SinTable[2048 - Angle] |
418 AngleSin.QWordValue:= SinTable[Angle] |
|
419 else |
|
420 AngleSin.QWordValue:= SinTable[2048 - Angle] |
408 end; |
421 end; |
409 |
422 |
410 function AngleCos(const Angle: Longword): hwFloat; |
423 function AngleCos(const Angle: Longword): hwFloat; |
411 begin |
424 begin |
412 //TryDo((Angle >= 0) and (Angle <= 2048), 'Cos param exceeds limits', true); |
425 //TryDo((Angle >= 0) and (Angle <= 2048), 'Cos param exceeds limits', true); |
413 AngleCos.isNegative:= Angle > 1024; |
426 AngleCos.isNegative:= Angle > 1024; |
414 if Angle < 1024 then AngleCos.QWordValue:= SinTable[1024 - Angle] |
427 if Angle < 1024 then |
415 else AngleCos.QWordValue:= SinTable[Angle - 1024] |
428 AngleCos.QWordValue:= SinTable[1024 - Angle] |
|
429 else |
|
430 AngleCos.QWordValue:= SinTable[Angle - 1024] |
416 end; |
431 end; |
417 |
432 |
418 function isZero(const z: hwFloat): boolean; inline; |
433 function isZero(const z: hwFloat): boolean; inline; |
419 begin |
434 begin |
420 isZero := z.QWordValue = 0; |
435 isZero := z.QWordValue = 0; |
421 end; |
436 end; |
422 {$ENDIF} |
437 {$ENDIF} |
423 |
438 |
424 end. |
439 end. |